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 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 23*acbc304dSjohnlev * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * The debugger/"PROM" interface layer 317c478bd9Sstevel@tonic-gate * 327c478bd9Sstevel@tonic-gate * (it makes more sense on SPARC) 337c478bd9Sstevel@tonic-gate */ 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_dpi_impl.h> 367c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_kdi.h> 377c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_umemglue.h> 387c478bd9Sstevel@tonic-gate #include <kmdb/kaif.h> 397c478bd9Sstevel@tonic-gate #include <kmdb/kaif_asmutil.h> 407c478bd9Sstevel@tonic-gate #include <mdb/mdb_err.h> 417c478bd9Sstevel@tonic-gate #include <mdb/mdb_debug.h> 427c478bd9Sstevel@tonic-gate #include <mdb/mdb_isautil.h> 437c478bd9Sstevel@tonic-gate #include <mdb/mdb_io_impl.h> 447c478bd9Sstevel@tonic-gate #include <mdb/mdb_kreg.h> 457c478bd9Sstevel@tonic-gate #include <mdb/mdb.h> 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate #include <sys/types.h> 487c478bd9Sstevel@tonic-gate #include <sys/segments.h> 497c478bd9Sstevel@tonic-gate #include <sys/bitmap.h> 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate kaif_cpusave_t *kaif_cpusave; 527c478bd9Sstevel@tonic-gate int kaif_ncpusave; 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate kaif_drreg_t kaif_drreg; 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate uint32_t kaif_waptmap; 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate #ifndef __amd64 597c478bd9Sstevel@tonic-gate /* Used to track the current set of valid kernel selectors. */ 607c478bd9Sstevel@tonic-gate uint32_t kaif_cs; 617c478bd9Sstevel@tonic-gate uint32_t kaif_ds; 627c478bd9Sstevel@tonic-gate uint32_t kaif_fs; 637c478bd9Sstevel@tonic-gate uint32_t kaif_gs; 647c478bd9Sstevel@tonic-gate #endif 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate uint_t kaif_msr_wrexit_msr; 677c478bd9Sstevel@tonic-gate uint64_t *kaif_msr_wrexit_valp; 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate uintptr_t kaif_kernel_handler; 707c478bd9Sstevel@tonic-gate uintptr_t kaif_sys_sysenter; 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate int kaif_trap_switch; 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate void (*kaif_modchg_cb)(struct modctl *, int); 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate #define KAIF_MEMRANGES_MAX 2 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate kaif_memrange_t kaif_memranges[KAIF_MEMRANGES_MAX]; 797c478bd9Sstevel@tonic-gate int kaif_nmemranges; 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate enum { 827c478bd9Sstevel@tonic-gate M_SYSRET = 0x07, /* after M_ESC */ 837c478bd9Sstevel@tonic-gate M_ESC = 0x0f, 847c478bd9Sstevel@tonic-gate M_SYSEXIT = 0x35, /* after M_ESC */ 857c478bd9Sstevel@tonic-gate M_REX_LO = 0x40, /* first REX prefix */ 867c478bd9Sstevel@tonic-gate M_REX_HI = 0x4f, /* last REX prefix */ 877c478bd9Sstevel@tonic-gate M_PUSHF = 0x9c, /* pushfl and pushfq */ 887c478bd9Sstevel@tonic-gate M_POPF = 0x9d, /* popfl and popfq */ 897c478bd9Sstevel@tonic-gate M_INT3 = 0xcc, 907c478bd9Sstevel@tonic-gate M_INTX = 0xcd, 917c478bd9Sstevel@tonic-gate M_INTO = 0xce, 927c478bd9Sstevel@tonic-gate M_IRET = 0xcf, 937c478bd9Sstevel@tonic-gate M_CLI = 0xfa, 947c478bd9Sstevel@tonic-gate M_STI = 0xfb 957c478bd9Sstevel@tonic-gate }; 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate #define KAIF_BREAKPOINT_INSTR M_INT3 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate #define KAIF_WPPRIV2ID(wp) (int)(uintptr_t)((wp)->wp_priv) 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate #ifdef __amd64 1027c478bd9Sstevel@tonic-gate #define FLAGS_REG_NAME "rflags" 1037c478bd9Sstevel@tonic-gate #else 1047c478bd9Sstevel@tonic-gate #define FLAGS_REG_NAME "eflags" 1057c478bd9Sstevel@tonic-gate #endif 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate /* 1087c478bd9Sstevel@tonic-gate * Called during normal debugger operation and during debugger faults. 1097c478bd9Sstevel@tonic-gate */ 1107c478bd9Sstevel@tonic-gate static void 1117c478bd9Sstevel@tonic-gate kaif_enter_mon(void) 1127c478bd9Sstevel@tonic-gate { 1137c478bd9Sstevel@tonic-gate char c; 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate for (;;) { 1167c478bd9Sstevel@tonic-gate mdb_iob_printf(mdb.m_out, 1177c478bd9Sstevel@tonic-gate "%s: Do you really want to reboot? (y/n) ", 1187c478bd9Sstevel@tonic-gate mdb.m_pname); 1197c478bd9Sstevel@tonic-gate mdb_iob_flush(mdb.m_out); 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate while (IOP_READ(mdb.m_term, &c, 1) != 1) 1227c478bd9Sstevel@tonic-gate continue; 1237c478bd9Sstevel@tonic-gate mdb_iob_printf(mdb.m_out, "%c%s", c, (c == '\n' ? "" : "\n")); 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate if (c == 'n' || c == 'N') 1267c478bd9Sstevel@tonic-gate return; 1277c478bd9Sstevel@tonic-gate else if (c == 'y' || c == 'Y') { 1287c478bd9Sstevel@tonic-gate mdb_iob_printf(mdb.m_out, "Rebooting...\n"); 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate kmdb_dpi_reboot(); 1317c478bd9Sstevel@tonic-gate } 1327c478bd9Sstevel@tonic-gate } 1337c478bd9Sstevel@tonic-gate } 1347c478bd9Sstevel@tonic-gate 135*acbc304dSjohnlev static kaif_cpusave_t * 136*acbc304dSjohnlev kaif_cpuid2save(int cpuid) 137*acbc304dSjohnlev { 138*acbc304dSjohnlev kaif_cpusave_t *save; 139*acbc304dSjohnlev 140*acbc304dSjohnlev if (cpuid == DPI_MASTER_CPUID) 141*acbc304dSjohnlev return (&kaif_cpusave[kaif_master_cpuid]); 142*acbc304dSjohnlev 143*acbc304dSjohnlev if (cpuid < 0 || cpuid >= kaif_ncpusave) { 144*acbc304dSjohnlev (void) set_errno(EINVAL); 145*acbc304dSjohnlev return (NULL); 146*acbc304dSjohnlev } 147*acbc304dSjohnlev 148*acbc304dSjohnlev save = &kaif_cpusave[cpuid]; 149*acbc304dSjohnlev 150*acbc304dSjohnlev if (save->krs_cpu_state != KAIF_CPU_STATE_MASTER && 151*acbc304dSjohnlev save->krs_cpu_state != KAIF_CPU_STATE_SLAVE) { 152*acbc304dSjohnlev (void) set_errno(EINVAL); 153*acbc304dSjohnlev return (NULL); 154*acbc304dSjohnlev } 155*acbc304dSjohnlev 156*acbc304dSjohnlev return (save); 157*acbc304dSjohnlev } 158*acbc304dSjohnlev 1597c478bd9Sstevel@tonic-gate static int 1607c478bd9Sstevel@tonic-gate kaif_get_cpu_state(int cpuid) 1617c478bd9Sstevel@tonic-gate { 162*acbc304dSjohnlev kaif_cpusave_t *save; 1637c478bd9Sstevel@tonic-gate 164*acbc304dSjohnlev if ((save = kaif_cpuid2save(cpuid)) == NULL) 165*acbc304dSjohnlev return (-1); /* errno is set for us */ 1667c478bd9Sstevel@tonic-gate 167*acbc304dSjohnlev switch (save->krs_cpu_state) { 1687c478bd9Sstevel@tonic-gate case KAIF_CPU_STATE_MASTER: 1697c478bd9Sstevel@tonic-gate return (DPI_CPU_STATE_MASTER); 1707c478bd9Sstevel@tonic-gate case KAIF_CPU_STATE_SLAVE: 1717c478bd9Sstevel@tonic-gate return (DPI_CPU_STATE_SLAVE); 1727c478bd9Sstevel@tonic-gate default: 1737c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 1747c478bd9Sstevel@tonic-gate } 1757c478bd9Sstevel@tonic-gate } 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate static int 1787c478bd9Sstevel@tonic-gate kaif_get_master_cpuid(void) 1797c478bd9Sstevel@tonic-gate { 1807c478bd9Sstevel@tonic-gate return (kaif_master_cpuid); 1817c478bd9Sstevel@tonic-gate } 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate static const mdb_tgt_gregset_t * 1847c478bd9Sstevel@tonic-gate kaif_get_gregs(int cpuid) 1857c478bd9Sstevel@tonic-gate { 186*acbc304dSjohnlev kaif_cpusave_t *save; 1877c478bd9Sstevel@tonic-gate 188*acbc304dSjohnlev if ((save = kaif_cpuid2save(cpuid)) == NULL) 189*acbc304dSjohnlev return (NULL); /* errno is set for us */ 1907c478bd9Sstevel@tonic-gate 191*acbc304dSjohnlev return (save->krs_gregs); 1927c478bd9Sstevel@tonic-gate } 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate typedef struct kaif_reg_synonyms { 1957c478bd9Sstevel@tonic-gate const char *rs_syn; 1967c478bd9Sstevel@tonic-gate const char *rs_name; 1977c478bd9Sstevel@tonic-gate } kaif_reg_synonyms_t; 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate static kreg_t * 200*acbc304dSjohnlev kaif_find_regp(const char *regname) 2017c478bd9Sstevel@tonic-gate { 2027c478bd9Sstevel@tonic-gate static const kaif_reg_synonyms_t synonyms[] = { 2037c478bd9Sstevel@tonic-gate #ifdef __amd64 2047c478bd9Sstevel@tonic-gate { "pc", "rip" }, 2057c478bd9Sstevel@tonic-gate { "sp", "rsp" }, 2067c478bd9Sstevel@tonic-gate { "fp", "rbp" }, 2077c478bd9Sstevel@tonic-gate #else 2087c478bd9Sstevel@tonic-gate { "pc", "eip" }, 2097c478bd9Sstevel@tonic-gate { "sp", "esp" }, 2107c478bd9Sstevel@tonic-gate { "fp", "ebp" }, 2117c478bd9Sstevel@tonic-gate #endif 2127c478bd9Sstevel@tonic-gate { "tt", "trapno" } 2137c478bd9Sstevel@tonic-gate }; 214*acbc304dSjohnlev 215*acbc304dSjohnlev kaif_cpusave_t *save; 2167c478bd9Sstevel@tonic-gate int i; 2177c478bd9Sstevel@tonic-gate 218*acbc304dSjohnlev save = kaif_cpuid2save(DPI_MASTER_CPUID); 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate for (i = 0; i < sizeof (synonyms) / sizeof (synonyms[0]); i++) { 2217c478bd9Sstevel@tonic-gate if (strcmp(synonyms[i].rs_syn, regname) == 0) 2227c478bd9Sstevel@tonic-gate regname = synonyms[i].rs_name; 2237c478bd9Sstevel@tonic-gate } 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate for (i = 0; mdb_isa_kregs[i].rd_name != NULL; i++) { 2267c478bd9Sstevel@tonic-gate const mdb_tgt_regdesc_t *rd = &mdb_isa_kregs[i]; 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate if (strcmp(rd->rd_name, regname) == 0) 229*acbc304dSjohnlev return (&save->krs_gregs->kregs[rd->rd_num]); 2307c478bd9Sstevel@tonic-gate } 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate (void) set_errno(ENOENT); 2337c478bd9Sstevel@tonic-gate return (NULL); 2347c478bd9Sstevel@tonic-gate } 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2377c478bd9Sstevel@tonic-gate static int 238*acbc304dSjohnlev kaif_get_register(const char *regname, kreg_t *valp) 2397c478bd9Sstevel@tonic-gate { 2407c478bd9Sstevel@tonic-gate kreg_t *regp; 2417c478bd9Sstevel@tonic-gate 242*acbc304dSjohnlev if ((regp = kaif_find_regp(regname)) == NULL) 2437c478bd9Sstevel@tonic-gate return (-1); 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate *valp = *regp; 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate return (0); 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate static int 251*acbc304dSjohnlev kaif_set_register(const char *regname, kreg_t val) 2527c478bd9Sstevel@tonic-gate { 2537c478bd9Sstevel@tonic-gate kreg_t *regp; 2547c478bd9Sstevel@tonic-gate 255*acbc304dSjohnlev if ((regp = kaif_find_regp(regname)) == NULL) 2567c478bd9Sstevel@tonic-gate return (-1); 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate *regp = val; 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate return (0); 2617c478bd9Sstevel@tonic-gate } 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate static int 2647c478bd9Sstevel@tonic-gate kaif_brkpt_arm(uintptr_t addr, mdb_instr_t *instrp) 2657c478bd9Sstevel@tonic-gate { 2667c478bd9Sstevel@tonic-gate mdb_instr_t bkpt = KAIF_BREAKPOINT_INSTR; 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate if (mdb_tgt_vread(mdb.m_target, instrp, 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 if (mdb_tgt_vwrite(mdb.m_target, &bkpt, sizeof (mdb_instr_t), addr) != 2737c478bd9Sstevel@tonic-gate sizeof (mdb_instr_t)) 2747c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate return (0); 2777c478bd9Sstevel@tonic-gate } 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate static int 2807c478bd9Sstevel@tonic-gate kaif_brkpt_disarm(uintptr_t addr, mdb_instr_t instrp) 2817c478bd9Sstevel@tonic-gate { 2827c478bd9Sstevel@tonic-gate if (mdb_tgt_vwrite(mdb.m_target, &instrp, sizeof (mdb_instr_t), addr) != 2837c478bd9Sstevel@tonic-gate sizeof (mdb_instr_t)) 2847c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate return (0); 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate /* 2907c478bd9Sstevel@tonic-gate * Intel watchpoints are even more fun than SPARC ones. The Intel architecture 2917c478bd9Sstevel@tonic-gate * manuals refer to watchpoints as breakpoints. For consistency with the 2927c478bd9Sstevel@tonic-gate * terminology used in other portions of kmdb, we will, however, refer to them 2937c478bd9Sstevel@tonic-gate * as watchpoints. 2947c478bd9Sstevel@tonic-gate * 2957c478bd9Sstevel@tonic-gate * Execute, data write, I/O read/write, and data read/write watchpoints are 2967c478bd9Sstevel@tonic-gate * supported by the hardware. Execute watchpoints must be one byte in length, 2977c478bd9Sstevel@tonic-gate * and must be placed on the first byte of the instruction to be watched. 2987c478bd9Sstevel@tonic-gate * Lengths of other watchpoints are more varied. 2997c478bd9Sstevel@tonic-gate * 3007c478bd9Sstevel@tonic-gate * Given that we already have a breakpoint facility, and given the restrictions 3017c478bd9Sstevel@tonic-gate * placed on execute watchpoints, we're going to disallow the creation of 3027c478bd9Sstevel@tonic-gate * execute watchpoints. The others will be fully supported. See the Debugging 3037c478bd9Sstevel@tonic-gate * chapter in both the IA32 and AMD64 System Programming books for more details. 3047c478bd9Sstevel@tonic-gate */ 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate #ifdef __amd64 3077c478bd9Sstevel@tonic-gate #define WAPT_DATA_MAX_SIZE 8 3087c478bd9Sstevel@tonic-gate #define WAPT_DATA_SIZES_MSG "1, 2, 4, or 8" 3097c478bd9Sstevel@tonic-gate #else 3107c478bd9Sstevel@tonic-gate #define WAPT_DATA_MAX_SIZE 4 3117c478bd9Sstevel@tonic-gate #define WAPT_DATA_SIZES_MSG "1, 2, or 4" 3127c478bd9Sstevel@tonic-gate #endif 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate static int 3157c478bd9Sstevel@tonic-gate kaif_wapt_validate(kmdb_wapt_t *wp) 3167c478bd9Sstevel@tonic-gate { 3177c478bd9Sstevel@tonic-gate if (wp->wp_type == DPI_WAPT_TYPE_IO) { 3187c478bd9Sstevel@tonic-gate if (wp->wp_wflags != (MDB_TGT_WA_R | MDB_TGT_WA_W)) { 3197c478bd9Sstevel@tonic-gate warn("I/O port watchpoints must be read/write\n"); 3207c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 3217c478bd9Sstevel@tonic-gate } 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate if (wp->wp_size != 1 && wp->wp_size != 2 && wp->wp_size != 4) { 3247c478bd9Sstevel@tonic-gate warn("I/O watchpoint size must be 1, 2, or 4 bytes\n"); 3257c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 3267c478bd9Sstevel@tonic-gate } 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate } else if (wp->wp_type == DPI_WAPT_TYPE_PHYS) { 3297c478bd9Sstevel@tonic-gate warn("physical address watchpoints are not supported on this " 3307c478bd9Sstevel@tonic-gate "platform\n"); 3317c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGTHWNOTSUP)); 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate } else { 3347c478bd9Sstevel@tonic-gate if (wp->wp_wflags != (MDB_TGT_WA_R | MDB_TGT_WA_W) && 3357c478bd9Sstevel@tonic-gate wp->wp_wflags != MDB_TGT_WA_W) { 3367c478bd9Sstevel@tonic-gate warn("watchpoints must be read/write or write-only\n"); 3377c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 3387c478bd9Sstevel@tonic-gate } 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate if ((wp->wp_size & -(wp->wp_size)) != wp->wp_size || 3417c478bd9Sstevel@tonic-gate wp->wp_size > WAPT_DATA_MAX_SIZE) { 3427c478bd9Sstevel@tonic-gate warn("data watchpoint size must be " WAPT_DATA_SIZES_MSG 3437c478bd9Sstevel@tonic-gate " bytes\n"); 3447c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 3457c478bd9Sstevel@tonic-gate } 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate } 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate if (wp->wp_addr & (wp->wp_size - 1)) { 3507c478bd9Sstevel@tonic-gate warn("%lu-byte watchpoints must be %lu-byte aligned\n", 3517c478bd9Sstevel@tonic-gate (ulong_t)wp->wp_size, (ulong_t)wp->wp_size); 3527c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate return (0); 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate static int 3597c478bd9Sstevel@tonic-gate kaif_wapt_reserve(kmdb_wapt_t *wp) 3607c478bd9Sstevel@tonic-gate { 3617c478bd9Sstevel@tonic-gate int id; 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate for (id = 0; id <= KREG_MAXWPIDX; id++) { 3647c478bd9Sstevel@tonic-gate if (!BT_TEST(&kaif_waptmap, id)) { 3657c478bd9Sstevel@tonic-gate /* found one */ 3667c478bd9Sstevel@tonic-gate BT_SET(&kaif_waptmap, id); 3677c478bd9Sstevel@tonic-gate wp->wp_priv = (void *)(uintptr_t)id; 3687c478bd9Sstevel@tonic-gate return (0); 3697c478bd9Sstevel@tonic-gate } 3707c478bd9Sstevel@tonic-gate } 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate return (set_errno(EMDB_WPTOOMANY)); 3737c478bd9Sstevel@tonic-gate } 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate static void 3767c478bd9Sstevel@tonic-gate kaif_wapt_release(kmdb_wapt_t *wp) 3777c478bd9Sstevel@tonic-gate { 3787c478bd9Sstevel@tonic-gate int id = KAIF_WPPRIV2ID(wp); 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate ASSERT(BT_TEST(&kaif_waptmap, id)); 3817c478bd9Sstevel@tonic-gate BT_CLEAR(&kaif_waptmap, id); 3827c478bd9Sstevel@tonic-gate } 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3857c478bd9Sstevel@tonic-gate static void 3867c478bd9Sstevel@tonic-gate kaif_wapt_arm(kmdb_wapt_t *wp) 3877c478bd9Sstevel@tonic-gate { 3887c478bd9Sstevel@tonic-gate uint_t rw; 3897c478bd9Sstevel@tonic-gate int hwid = KAIF_WPPRIV2ID(wp); 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate ASSERT(BT_TEST(&kaif_waptmap, hwid)); 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate if (wp->wp_type == DPI_WAPT_TYPE_IO) 3947c478bd9Sstevel@tonic-gate rw = KREG_DRCTL_WP_IORW; 3957c478bd9Sstevel@tonic-gate else if (wp->wp_wflags & MDB_TGT_WA_R) 3967c478bd9Sstevel@tonic-gate rw = KREG_DRCTL_WP_RW; 3977c478bd9Sstevel@tonic-gate else if (wp->wp_wflags & MDB_TGT_WA_X) 3987c478bd9Sstevel@tonic-gate rw = KREG_DRCTL_WP_EXEC; 3997c478bd9Sstevel@tonic-gate else 4007c478bd9Sstevel@tonic-gate rw = KREG_DRCTL_WP_WONLY; 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate kaif_drreg.dr_addr[hwid] = wp->wp_addr; 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate kaif_drreg.dr_ctl &= ~KREG_DRCTL_WP_MASK(hwid); 4057c478bd9Sstevel@tonic-gate kaif_drreg.dr_ctl |= KREG_DRCTL_WP_LENRW(hwid, wp->wp_size - 1, rw); 4067c478bd9Sstevel@tonic-gate kaif_drreg.dr_ctl |= KREG_DRCTL_WPEN(hwid); 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4107c478bd9Sstevel@tonic-gate static void 4117c478bd9Sstevel@tonic-gate kaif_wapt_disarm(kmdb_wapt_t *wp) 4127c478bd9Sstevel@tonic-gate { 4137c478bd9Sstevel@tonic-gate int hwid = KAIF_WPPRIV2ID(wp); 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate ASSERT(BT_TEST(&kaif_waptmap, hwid)); 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate kaif_drreg.dr_addr[hwid] = 0; 4187c478bd9Sstevel@tonic-gate kaif_drreg.dr_ctl &= ~(KREG_DRCTL_WP_MASK(hwid) | 4197c478bd9Sstevel@tonic-gate KREG_DRCTL_WPEN_MASK(hwid)); 4207c478bd9Sstevel@tonic-gate } 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4237c478bd9Sstevel@tonic-gate static int 4247c478bd9Sstevel@tonic-gate kaif_wapt_match(kmdb_wapt_t *wp) 4257c478bd9Sstevel@tonic-gate { 4267c478bd9Sstevel@tonic-gate int hwid = KAIF_WPPRIV2ID(wp); 4277c478bd9Sstevel@tonic-gate uint32_t mask = KREG_DRSTAT_WP_MASK(hwid); 4287c478bd9Sstevel@tonic-gate int n = 0; 4297c478bd9Sstevel@tonic-gate int i; 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate ASSERT(BT_TEST(&kaif_waptmap, hwid)); 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate for (i = 0; i < kaif_ncpusave; i++) 4347c478bd9Sstevel@tonic-gate n += (kaif_cpusave[i].krs_dr.dr_stat & mask) != 0; 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate return (n); 4377c478bd9Sstevel@tonic-gate } 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate static int 4407c478bd9Sstevel@tonic-gate kaif_step(void) 4417c478bd9Sstevel@tonic-gate { 4427c478bd9Sstevel@tonic-gate kreg_t pc, fl, oldfl, newfl, sp; 4437c478bd9Sstevel@tonic-gate mdb_tgt_addr_t npc; 4447c478bd9Sstevel@tonic-gate mdb_instr_t instr; 4457c478bd9Sstevel@tonic-gate int emulated = 0, rchk = 0; 4467c478bd9Sstevel@tonic-gate size_t pcoff = 0; 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register("pc", &pc); 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate if ((npc = mdb_dis_nextins(mdb.m_disasm, mdb.m_target, 4517c478bd9Sstevel@tonic-gate MDB_TGT_AS_VIRT, pc)) == pc) { 4527c478bd9Sstevel@tonic-gate warn("failed to decode instruction at %a for step\n", pc); 4537c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 4547c478bd9Sstevel@tonic-gate } 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate /* 4577c478bd9Sstevel@tonic-gate * Stepping behavior depends on the type of instruction. It does not 4587c478bd9Sstevel@tonic-gate * depend on the presence of a REX prefix, as the action we take for a 4597c478bd9Sstevel@tonic-gate * given instruction doesn't currently vary for 32-bit instructions 4607c478bd9Sstevel@tonic-gate * versus their 64-bit counterparts. 4617c478bd9Sstevel@tonic-gate */ 4627c478bd9Sstevel@tonic-gate do { 4637c478bd9Sstevel@tonic-gate if (mdb_tgt_vread(mdb.m_target, &instr, sizeof (mdb_instr_t), 4647c478bd9Sstevel@tonic-gate pc + pcoff) != sizeof (mdb_instr_t)) { 4657c478bd9Sstevel@tonic-gate warn("failed to read at %p for step", 4667c478bd9Sstevel@tonic-gate (void *)(pc + pcoff)); 4677c478bd9Sstevel@tonic-gate return (-1); 4687c478bd9Sstevel@tonic-gate } 4697c478bd9Sstevel@tonic-gate } while (pcoff++, (instr >= M_REX_LO && instr <= M_REX_HI && !rchk++)); 4707c478bd9Sstevel@tonic-gate 4717c478bd9Sstevel@tonic-gate switch (instr) { 4727c478bd9Sstevel@tonic-gate case M_IRET: 4737c478bd9Sstevel@tonic-gate warn("iret cannot be stepped\n"); 4747c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP)); 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate case M_INT3: 4777c478bd9Sstevel@tonic-gate case M_INTX: 4787c478bd9Sstevel@tonic-gate case M_INTO: 4797c478bd9Sstevel@tonic-gate warn("int cannot be stepped\n"); 4807c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP)); 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate case M_ESC: 4837c478bd9Sstevel@tonic-gate if (mdb_tgt_vread(mdb.m_target, &instr, sizeof (mdb_instr_t), 4847c478bd9Sstevel@tonic-gate pc + pcoff) != sizeof (mdb_instr_t)) { 4857c478bd9Sstevel@tonic-gate warn("failed to read at %p for step", 4867c478bd9Sstevel@tonic-gate (void *)(pc + pcoff)); 4877c478bd9Sstevel@tonic-gate return (-1); 4887c478bd9Sstevel@tonic-gate } 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate switch (instr) { 4917c478bd9Sstevel@tonic-gate case M_SYSRET: 4927c478bd9Sstevel@tonic-gate warn("sysret cannot be stepped\n"); 4937c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP)); 4947c478bd9Sstevel@tonic-gate case M_SYSEXIT: 4957c478bd9Sstevel@tonic-gate warn("sysexit cannot be stepped\n"); 4967c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP)); 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate break; 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate /* 5017c478bd9Sstevel@tonic-gate * Some instructions need to be emulated. We need to prevent direct 5027c478bd9Sstevel@tonic-gate * manipulations of EFLAGS, so we'll emulate cli, sti. pushfl and 5037c478bd9Sstevel@tonic-gate * popfl also receive special handling, as they manipulate both EFLAGS 5047c478bd9Sstevel@tonic-gate * and %esp. 5057c478bd9Sstevel@tonic-gate */ 5067c478bd9Sstevel@tonic-gate case M_CLI: 5077c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl); 5087c478bd9Sstevel@tonic-gate fl &= ~KREG_EFLAGS_IF_MASK; 5097c478bd9Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, fl); 5107c478bd9Sstevel@tonic-gate 5117c478bd9Sstevel@tonic-gate emulated = 1; 5127c478bd9Sstevel@tonic-gate break; 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate case M_STI: 5157c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl); 5167c478bd9Sstevel@tonic-gate fl |= (1 << KREG_EFLAGS_IF_SHIFT); 5177c478bd9Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, fl); 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate emulated = 1; 5207c478bd9Sstevel@tonic-gate break; 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate case M_POPF: 5237c478bd9Sstevel@tonic-gate /* 5247c478bd9Sstevel@tonic-gate * popfl will restore a pushed EFLAGS from the stack, and could 5257c478bd9Sstevel@tonic-gate * in so doing cause IF to be turned on, if only for a a brief 5267c478bd9Sstevel@tonic-gate * period. To avoid this, we'll secretly replace the stack's 5277c478bd9Sstevel@tonic-gate * EFLAGS with our decaffeinated brand. We'll then manually 5287c478bd9Sstevel@tonic-gate * load our EFLAGS copy with the real verion after the step. 5297c478bd9Sstevel@tonic-gate */ 5307c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register("sp", &sp); 5317c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl); 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate if (mdb_tgt_vread(mdb.m_target, &newfl, sizeof (kreg_t), 5347c478bd9Sstevel@tonic-gate sp) != sizeof (kreg_t)) { 5357c478bd9Sstevel@tonic-gate warn("failed to read " FLAGS_REG_NAME 5367c478bd9Sstevel@tonic-gate " at %p for popfl step\n", (void *)sp); 5377c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */ 5387c478bd9Sstevel@tonic-gate } 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate fl = (fl & ~KREG_EFLAGS_IF_MASK) | KREG_EFLAGS_TF_MASK; 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate if (mdb_tgt_vwrite(mdb.m_target, &fl, sizeof (kreg_t), 5437c478bd9Sstevel@tonic-gate sp) != sizeof (kreg_t)) { 5447c478bd9Sstevel@tonic-gate warn("failed to update " FLAGS_REG_NAME 5457c478bd9Sstevel@tonic-gate " at %p for popfl step\n", (void *)sp); 5467c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */ 5477c478bd9Sstevel@tonic-gate } 5487c478bd9Sstevel@tonic-gate break; 5497c478bd9Sstevel@tonic-gate } 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate if (emulated) { 5527c478bd9Sstevel@tonic-gate (void) kmdb_dpi_set_register("pc", npc); 5537c478bd9Sstevel@tonic-gate return (0); 5547c478bd9Sstevel@tonic-gate } 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate /* Do the step with IF off, and TF (step) on */ 5577c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &oldfl); 5587c478bd9Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, 5597c478bd9Sstevel@tonic-gate ((oldfl | (1 << KREG_EFLAGS_TF_SHIFT)) & ~KREG_EFLAGS_IF_MASK)); 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate kmdb_dpi_resume_master(); /* ... there and back again ... */ 5627c478bd9Sstevel@tonic-gate 5637c478bd9Sstevel@tonic-gate /* EFLAGS has now changed, and may require tuning */ 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate switch (instr) { 5667c478bd9Sstevel@tonic-gate case M_POPF: 5677c478bd9Sstevel@tonic-gate /* 5687c478bd9Sstevel@tonic-gate * Use the EFLAGS we grabbed before the pop - see the pre-step 5697c478bd9Sstevel@tonic-gate * M_POPFL comment. 5707c478bd9Sstevel@tonic-gate */ 5717c478bd9Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, newfl); 5727c478bd9Sstevel@tonic-gate return (0); 5737c478bd9Sstevel@tonic-gate 5747c478bd9Sstevel@tonic-gate case M_PUSHF: 5757c478bd9Sstevel@tonic-gate /* 5767c478bd9Sstevel@tonic-gate * We pushed our modified EFLAGS (with IF and TF turned off) 5777c478bd9Sstevel@tonic-gate * onto the stack. Replace the pushed version with our 5787c478bd9Sstevel@tonic-gate * unmodified one. 5797c478bd9Sstevel@tonic-gate */ 5807c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register("sp", &sp); 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate if (mdb_tgt_vwrite(mdb.m_target, &oldfl, sizeof (kreg_t), 5837c478bd9Sstevel@tonic-gate sp) != sizeof (kreg_t)) { 5847c478bd9Sstevel@tonic-gate warn("failed to update pushed " FLAGS_REG_NAME 5857c478bd9Sstevel@tonic-gate " at %p after pushfl step\n", (void *)sp); 5867c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */ 5877c478bd9Sstevel@tonic-gate } 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate /* Go back to using the EFLAGS we were using before the step */ 5907c478bd9Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, oldfl); 5917c478bd9Sstevel@tonic-gate return (0); 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate default: 5947c478bd9Sstevel@tonic-gate /* 5957c478bd9Sstevel@tonic-gate * The stepped instruction may have altered EFLAGS. We only 5967c478bd9Sstevel@tonic-gate * really care about the value of IF, and we know the stepped 5977c478bd9Sstevel@tonic-gate * instruction didn't alter it, so we can simply copy the 5987c478bd9Sstevel@tonic-gate * pre-step value. We'll also need to turn TF back off. 5997c478bd9Sstevel@tonic-gate */ 6007c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl); 6017c478bd9Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, 6027c478bd9Sstevel@tonic-gate ((fl & ~(KREG_EFLAGS_TF_MASK|KREG_EFLAGS_IF_MASK)) | 6037c478bd9Sstevel@tonic-gate (oldfl & KREG_EFLAGS_IF_MASK))); 6047c478bd9Sstevel@tonic-gate return (0); 6057c478bd9Sstevel@tonic-gate } 6067c478bd9Sstevel@tonic-gate } 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate /* 6097c478bd9Sstevel@tonic-gate * The target has already configured the chip for branch step, leaving us to 6107c478bd9Sstevel@tonic-gate * actually make the machine go. Due to a number of issues involving 6117c478bd9Sstevel@tonic-gate * the potential alteration of system state via instructions like sti, cli, 6127c478bd9Sstevel@tonic-gate * pushfl, and popfl, we're going to treat this like a normal system resume. 6137c478bd9Sstevel@tonic-gate * All CPUs will be released, on the kernel's IDT. Our primary concern is 6147c478bd9Sstevel@tonic-gate * the alteration/storage of our TF'd EFLAGS via pushfl and popfl. There's no 6157c478bd9Sstevel@tonic-gate * real workaround - we don't have opcode breakpoints - so the best we can do is 6167c478bd9Sstevel@tonic-gate * to ensure that the world won't end if someone does bad things to EFLAGS. 6177c478bd9Sstevel@tonic-gate * 6187c478bd9Sstevel@tonic-gate * Two things can happen: 6197c478bd9Sstevel@tonic-gate * 1. EFLAGS.TF may be cleared, either maliciously or via a popfl from saved 6207c478bd9Sstevel@tonic-gate * state. The CPU will continue execution beyond the branch, and will not 6217c478bd9Sstevel@tonic-gate * reenter the debugger unless brought/sent in by other means. 6227c478bd9Sstevel@tonic-gate * 2. Someone may pushlf the TF'd EFLAGS, and may stash a copy of it somewhere. 6237c478bd9Sstevel@tonic-gate * When the saved version is popfl'd back into place, the debugger will be 6247c478bd9Sstevel@tonic-gate * re-entered on a single-step trap. 6257c478bd9Sstevel@tonic-gate */ 6267c478bd9Sstevel@tonic-gate static void 6277c478bd9Sstevel@tonic-gate kaif_step_branch(void) 6287c478bd9Sstevel@tonic-gate { 6297c478bd9Sstevel@tonic-gate kreg_t fl; 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl); 6327c478bd9Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, 6337c478bd9Sstevel@tonic-gate (fl | (1 << KREG_EFLAGS_TF_SHIFT))); 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate kmdb_dpi_resume_master(); 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, fl); 6387c478bd9Sstevel@tonic-gate } 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6417c478bd9Sstevel@tonic-gate static uintptr_t 6427c478bd9Sstevel@tonic-gate kaif_call(uintptr_t funcva, uint_t argc, const uintptr_t argv[]) 6437c478bd9Sstevel@tonic-gate { 6447c478bd9Sstevel@tonic-gate return (kaif_invoke(funcva, argc, argv)); 6457c478bd9Sstevel@tonic-gate } 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate static void 648*acbc304dSjohnlev dump_crumb(kaif_crumb_t *krmp) 6497c478bd9Sstevel@tonic-gate { 650*acbc304dSjohnlev kaif_crumb_t krm; 651*acbc304dSjohnlev 652*acbc304dSjohnlev if (mdb_vread(&krm, sizeof (kaif_crumb_t), (uintptr_t)krmp) != 653*acbc304dSjohnlev sizeof (kaif_crumb_t)) { 654*acbc304dSjohnlev warn("failed to read crumb at %p", krmp); 655*acbc304dSjohnlev return; 656*acbc304dSjohnlev } 657*acbc304dSjohnlev 6587c478bd9Sstevel@tonic-gate mdb_printf("state: "); 659*acbc304dSjohnlev switch (krm.krm_cpu_state) { 6607c478bd9Sstevel@tonic-gate case KAIF_CPU_STATE_MASTER: 6617c478bd9Sstevel@tonic-gate mdb_printf("M"); 6627c478bd9Sstevel@tonic-gate break; 6637c478bd9Sstevel@tonic-gate case KAIF_CPU_STATE_SLAVE: 6647c478bd9Sstevel@tonic-gate mdb_printf("S"); 6657c478bd9Sstevel@tonic-gate break; 6667c478bd9Sstevel@tonic-gate default: 667*acbc304dSjohnlev mdb_printf("%d", krm.krm_cpu_state); 6687c478bd9Sstevel@tonic-gate } 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate mdb_printf(" trapno %3d sp %08x flag %d pc %p %A\n", 671*acbc304dSjohnlev krm.krm_trapno, krm.krm_sp, krm.krm_flag, krm.krm_pc, krm.krm_pc); 6727c478bd9Sstevel@tonic-gate } 6737c478bd9Sstevel@tonic-gate 6747c478bd9Sstevel@tonic-gate static void 6757c478bd9Sstevel@tonic-gate dump_crumbs(kaif_cpusave_t *save) 6767c478bd9Sstevel@tonic-gate { 6777c478bd9Sstevel@tonic-gate int i; 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate for (i = KAIF_NCRUMBS; i > 0; i--) { 6807c478bd9Sstevel@tonic-gate uint_t idx = (save->krs_curcrumbidx + i) % KAIF_NCRUMBS; 6817c478bd9Sstevel@tonic-gate dump_crumb(&save->krs_crumbs[idx]); 6827c478bd9Sstevel@tonic-gate } 6837c478bd9Sstevel@tonic-gate } 6847c478bd9Sstevel@tonic-gate 6857c478bd9Sstevel@tonic-gate static void 6867c478bd9Sstevel@tonic-gate kaif_dump_crumbs(uintptr_t addr, int cpuid) 6877c478bd9Sstevel@tonic-gate { 6887c478bd9Sstevel@tonic-gate int i; 6897c478bd9Sstevel@tonic-gate 6907c478bd9Sstevel@tonic-gate if (addr != NULL) { 691*acbc304dSjohnlev /* dump_crumb will protect us against bogus addresses */ 6927c478bd9Sstevel@tonic-gate dump_crumb((kaif_crumb_t *)addr); 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate } else if (cpuid != -1) { 695*acbc304dSjohnlev if (cpuid < 0 || cpuid >= kaif_ncpusave) 6967c478bd9Sstevel@tonic-gate return; 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate dump_crumbs(&kaif_cpusave[cpuid]); 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate } else { 7017c478bd9Sstevel@tonic-gate for (i = 0; i < kaif_ncpusave; i++) { 7027c478bd9Sstevel@tonic-gate kaif_cpusave_t *save = &kaif_cpusave[i]; 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate if (save->krs_cpu_state == KAIF_CPU_STATE_NONE) 7057c478bd9Sstevel@tonic-gate continue; 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate mdb_printf("%sCPU %d crumbs: (curidx %d)\n", 7087c478bd9Sstevel@tonic-gate (i == 0 ? "" : "\n"), i, save->krs_curcrumbidx); 7097c478bd9Sstevel@tonic-gate 7107c478bd9Sstevel@tonic-gate dump_crumbs(save); 7117c478bd9Sstevel@tonic-gate } 7127c478bd9Sstevel@tonic-gate } 7137c478bd9Sstevel@tonic-gate } 7147c478bd9Sstevel@tonic-gate 7157c478bd9Sstevel@tonic-gate static void 7167c478bd9Sstevel@tonic-gate kaif_modchg_register(void (*func)(struct modctl *, int)) 7177c478bd9Sstevel@tonic-gate { 7187c478bd9Sstevel@tonic-gate kaif_modchg_cb = func; 7197c478bd9Sstevel@tonic-gate } 7207c478bd9Sstevel@tonic-gate 7217c478bd9Sstevel@tonic-gate static void 7227c478bd9Sstevel@tonic-gate kaif_modchg_cancel(void) 7237c478bd9Sstevel@tonic-gate { 7247c478bd9Sstevel@tonic-gate ASSERT(kaif_modchg_cb != NULL); 7257c478bd9Sstevel@tonic-gate 7267c478bd9Sstevel@tonic-gate kaif_modchg_cb = NULL; 7277c478bd9Sstevel@tonic-gate } 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate void 7307c478bd9Sstevel@tonic-gate kaif_mod_loaded(struct modctl *modp) 7317c478bd9Sstevel@tonic-gate { 7327c478bd9Sstevel@tonic-gate if (kaif_modchg_cb != NULL) 7337c478bd9Sstevel@tonic-gate kaif_modchg_cb(modp, 1); 7347c478bd9Sstevel@tonic-gate } 7357c478bd9Sstevel@tonic-gate 7367c478bd9Sstevel@tonic-gate void 7377c478bd9Sstevel@tonic-gate kaif_mod_unloading(struct modctl *modp) 7387c478bd9Sstevel@tonic-gate { 7397c478bd9Sstevel@tonic-gate if (kaif_modchg_cb != NULL) 7407c478bd9Sstevel@tonic-gate kaif_modchg_cb(modp, 0); 7417c478bd9Sstevel@tonic-gate } 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate /* 7447c478bd9Sstevel@tonic-gate * On some processors, we'll need to clear a certain MSR before proceeding into 7457c478bd9Sstevel@tonic-gate * the debugger. Complicating matters, this MSR must be cleared before we take 7467c478bd9Sstevel@tonic-gate * any branches. We have patch points in every trap handler, which will cover 7477c478bd9Sstevel@tonic-gate * all entry paths for master CPUs. We also have a patch point in the slave 7487c478bd9Sstevel@tonic-gate * entry code. 7497c478bd9Sstevel@tonic-gate */ 7507c478bd9Sstevel@tonic-gate static void 7517c478bd9Sstevel@tonic-gate kaif_msr_add_clrentry(uint_t msr) 7527c478bd9Sstevel@tonic-gate { 7537c478bd9Sstevel@tonic-gate #ifdef __amd64 7547c478bd9Sstevel@tonic-gate uchar_t code[] = { 7557c478bd9Sstevel@tonic-gate 0x51, 0x50, 0x52, /* pushq %rcx, %rax, %rdx */ 7567c478bd9Sstevel@tonic-gate 0xb9, 0x00, 0x00, 0x00, 0x00, /* movl $MSRNUM, %ecx */ 7577c478bd9Sstevel@tonic-gate 0x31, 0xc0, /* clr %eax */ 7587c478bd9Sstevel@tonic-gate 0x31, 0xd2, /* clr %edx */ 7597c478bd9Sstevel@tonic-gate 0x0f, 0x30, /* wrmsr */ 7607c478bd9Sstevel@tonic-gate 0x5a, 0x58, 0x59 /* popq %rdx, %rax, %rcx */ 7617c478bd9Sstevel@tonic-gate }; 7627c478bd9Sstevel@tonic-gate uchar_t *patch = &code[4]; 7637c478bd9Sstevel@tonic-gate #else 7647c478bd9Sstevel@tonic-gate uchar_t code[] = { 7657c478bd9Sstevel@tonic-gate 0x60, /* pushal */ 7667c478bd9Sstevel@tonic-gate 0xb9, 0x00, 0x00, 0x00, 0x00, /* movl $MSRNUM, %ecx */ 7677c478bd9Sstevel@tonic-gate 0x31, 0xc0, /* clr %eax */ 7687c478bd9Sstevel@tonic-gate 0x31, 0xd2, /* clr %edx */ 7697c478bd9Sstevel@tonic-gate 0x0f, 0x30, /* wrmsr */ 7707c478bd9Sstevel@tonic-gate 0x61 /* popal */ 7717c478bd9Sstevel@tonic-gate }; 7727c478bd9Sstevel@tonic-gate uchar_t *patch = &code[2]; 7737c478bd9Sstevel@tonic-gate #endif 7747c478bd9Sstevel@tonic-gate 7757c478bd9Sstevel@tonic-gate bcopy(&msr, patch, sizeof (uint32_t)); 7767c478bd9Sstevel@tonic-gate 7777c478bd9Sstevel@tonic-gate kaif_idt_patch((caddr_t)code, sizeof (code)); 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate bcopy(code, &kaif_slave_entry_patch, sizeof (code)); 7807c478bd9Sstevel@tonic-gate } 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate static void 7837c478bd9Sstevel@tonic-gate kaif_msr_add_wrexit(uint_t msr, uint64_t *valp) 7847c478bd9Sstevel@tonic-gate { 7857c478bd9Sstevel@tonic-gate kaif_msr_wrexit_msr = msr; 7867c478bd9Sstevel@tonic-gate kaif_msr_wrexit_valp = valp; 7877c478bd9Sstevel@tonic-gate } 7887c478bd9Sstevel@tonic-gate 7897c478bd9Sstevel@tonic-gate static void 7907c478bd9Sstevel@tonic-gate kaif_msr_add(const kmdb_msr_t *msrs) 7917c478bd9Sstevel@tonic-gate { 7927c478bd9Sstevel@tonic-gate kmdb_msr_t *save; 7937c478bd9Sstevel@tonic-gate int nmsrs, i; 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate ASSERT(kaif_cpusave[0].krs_msr == NULL); 7967c478bd9Sstevel@tonic-gate 7977c478bd9Sstevel@tonic-gate for (i = 0; msrs[i].msr_num != 0; i++) { 7987c478bd9Sstevel@tonic-gate switch (msrs[i].msr_type) { 7997c478bd9Sstevel@tonic-gate case KMDB_MSR_CLEARENTRY: 8007c478bd9Sstevel@tonic-gate kaif_msr_add_clrentry(msrs[i].msr_num); 8017c478bd9Sstevel@tonic-gate break; 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate case KMDB_MSR_WRITEDELAY: 8047c478bd9Sstevel@tonic-gate kaif_msr_add_wrexit(msrs[i].msr_num, msrs[i].msr_valp); 8057c478bd9Sstevel@tonic-gate break; 8067c478bd9Sstevel@tonic-gate } 8077c478bd9Sstevel@tonic-gate } 8087c478bd9Sstevel@tonic-gate nmsrs = i + 1; /* we want to copy the terminating kmdb_msr_t too */ 8097c478bd9Sstevel@tonic-gate 8107c478bd9Sstevel@tonic-gate save = mdb_zalloc(sizeof (kmdb_msr_t) * nmsrs * kaif_ncpusave, 8117c478bd9Sstevel@tonic-gate UM_SLEEP); 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate for (i = 0; i < kaif_ncpusave; i++) { 8147c478bd9Sstevel@tonic-gate bcopy(msrs, &save[nmsrs * i], sizeof (kmdb_msr_t) * nmsrs); 8157c478bd9Sstevel@tonic-gate kaif_cpusave[i].krs_msr = &save[nmsrs * i]; 8167c478bd9Sstevel@tonic-gate } 8177c478bd9Sstevel@tonic-gate } 8187c478bd9Sstevel@tonic-gate 8197c478bd9Sstevel@tonic-gate static uint64_t 8207c478bd9Sstevel@tonic-gate kaif_msr_get(int cpuid, uint_t num) 8217c478bd9Sstevel@tonic-gate { 822*acbc304dSjohnlev kaif_cpusave_t *save; 8237c478bd9Sstevel@tonic-gate kmdb_msr_t *msr; 8247c478bd9Sstevel@tonic-gate int i; 8257c478bd9Sstevel@tonic-gate 826*acbc304dSjohnlev if ((save = kaif_cpuid2save(cpuid)) == NULL) 827*acbc304dSjohnlev return (-1); /* errno is set for us */ 828*acbc304dSjohnlev 829*acbc304dSjohnlev msr = save->krs_msr; 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate for (i = 0; msr[i].msr_num != 0; i++) { 8327c478bd9Sstevel@tonic-gate if (msr[i].msr_num == num && 8337c478bd9Sstevel@tonic-gate (msr[i].msr_type & KMDB_MSR_READ)) 8347c478bd9Sstevel@tonic-gate return (msr[i].msr_val); 8357c478bd9Sstevel@tonic-gate } 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate return (0); 8387c478bd9Sstevel@tonic-gate } 8397c478bd9Sstevel@tonic-gate 8407c478bd9Sstevel@tonic-gate int 8417c478bd9Sstevel@tonic-gate kaif_memrange_add(caddr_t base, size_t len) 8427c478bd9Sstevel@tonic-gate { 8437c478bd9Sstevel@tonic-gate kaif_memrange_t *mr = &kaif_memranges[kaif_nmemranges]; 8447c478bd9Sstevel@tonic-gate 8457c478bd9Sstevel@tonic-gate if (kaif_nmemranges == KAIF_MEMRANGES_MAX) 8467c478bd9Sstevel@tonic-gate return (set_errno(ENOSPC)); 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate /* 8497c478bd9Sstevel@tonic-gate * In the unlikely event that someone is stepping through this routine, 8507c478bd9Sstevel@tonic-gate * we need to make sure that kaif_memranges knows about the new range 8517c478bd9Sstevel@tonic-gate * before umem gets it. That way the entry code can recognize stacks 8527c478bd9Sstevel@tonic-gate * allocated from the new region. 8537c478bd9Sstevel@tonic-gate */ 8547c478bd9Sstevel@tonic-gate mr->mr_base = base; 8557c478bd9Sstevel@tonic-gate mr->mr_lim = base + len - 1; 8567c478bd9Sstevel@tonic-gate kaif_nmemranges++; 8577c478bd9Sstevel@tonic-gate 8587c478bd9Sstevel@tonic-gate if (mdb_umem_add(base, len) < 0) { 8597c478bd9Sstevel@tonic-gate kaif_nmemranges--; 8607c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate 8637c478bd9Sstevel@tonic-gate return (0); 8647c478bd9Sstevel@tonic-gate } 8657c478bd9Sstevel@tonic-gate 8667c478bd9Sstevel@tonic-gate void 8677c478bd9Sstevel@tonic-gate kaif_trap_set_debugger(void) 8687c478bd9Sstevel@tonic-gate { 8697c478bd9Sstevel@tonic-gate set_idt(&kaif_idtr); 8707c478bd9Sstevel@tonic-gate } 8717c478bd9Sstevel@tonic-gate 8727c478bd9Sstevel@tonic-gate void 8737c478bd9Sstevel@tonic-gate kaif_trap_set_saved(kaif_cpusave_t *cpusave) 8747c478bd9Sstevel@tonic-gate { 8757c478bd9Sstevel@tonic-gate set_idt(&cpusave->krs_idtr); 8767c478bd9Sstevel@tonic-gate } 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate static int 8797c478bd9Sstevel@tonic-gate kaif_init(kmdb_auxv_t *kav) 8807c478bd9Sstevel@tonic-gate { 8817c478bd9Sstevel@tonic-gate int i; 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate /* Allocate the per-CPU save areas */ 8847c478bd9Sstevel@tonic-gate kaif_cpusave = mdb_zalloc(sizeof (kaif_cpusave_t) * kav->kav_ncpu, 8857c478bd9Sstevel@tonic-gate UM_SLEEP); 8867c478bd9Sstevel@tonic-gate kaif_ncpusave = kav->kav_ncpu; 8877c478bd9Sstevel@tonic-gate 8887c478bd9Sstevel@tonic-gate for (i = 0; i < kaif_ncpusave; i++) { 889*acbc304dSjohnlev kaif_cpusave_t *save = &kaif_cpusave[i]; 8907c478bd9Sstevel@tonic-gate 891*acbc304dSjohnlev save->krs_cpu_id = i; 892*acbc304dSjohnlev save->krs_curcrumbidx = KAIF_NCRUMBS - 1; 893*acbc304dSjohnlev save->krs_curcrumb = &save->krs_crumbs[save->krs_curcrumbidx]; 8947c478bd9Sstevel@tonic-gate } 8957c478bd9Sstevel@tonic-gate 8967c478bd9Sstevel@tonic-gate kaif_idt_init(); 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate /* The initial selector set. Updated by the debugger-entry code */ 8997c478bd9Sstevel@tonic-gate #ifndef __amd64 9007c478bd9Sstevel@tonic-gate kaif_cs = BOOTCODE_SEL; 9017c478bd9Sstevel@tonic-gate kaif_ds = kaif_fs = kaif_gs = BOOTFLAT_SEL; 9027c478bd9Sstevel@tonic-gate #endif 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate kaif_memranges[0].mr_base = kav->kav_dseg; 9057c478bd9Sstevel@tonic-gate kaif_memranges[0].mr_lim = kav->kav_dseg + kav->kav_dseg_size - 1; 9067c478bd9Sstevel@tonic-gate kaif_nmemranges = 1; 9077c478bd9Sstevel@tonic-gate 9087c478bd9Sstevel@tonic-gate kaif_modchg_cb = NULL; 9097c478bd9Sstevel@tonic-gate 9107c478bd9Sstevel@tonic-gate kaif_waptmap = 0; 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate kaif_drreg.dr_ctl = KREG_DRCTL_RESERVED; 9137c478bd9Sstevel@tonic-gate kaif_drreg.dr_stat = KREG_DRSTAT_RESERVED; 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate kaif_msr_wrexit_msr = 0; 9167c478bd9Sstevel@tonic-gate kaif_msr_wrexit_valp = NULL; 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate kaif_trap_switch = (kav->kav_flags & KMDB_AUXV_FL_NOTRPSWTCH) == 0; 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate if ((kaif_sys_sysenter = kmdb_kdi_lookup_by_name("unix", 9217c478bd9Sstevel@tonic-gate "sys_sysenter")) == NULL) 9227c478bd9Sstevel@tonic-gate return (set_errno(ENOENT)); 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate return (0); 9257c478bd9Sstevel@tonic-gate } 9267c478bd9Sstevel@tonic-gate 9277c478bd9Sstevel@tonic-gate dpi_ops_t kmdb_dpi_ops = { 9287c478bd9Sstevel@tonic-gate kaif_init, 9297c478bd9Sstevel@tonic-gate kaif_activate, 9307c478bd9Sstevel@tonic-gate kaif_deactivate, 9317c478bd9Sstevel@tonic-gate kaif_enter_mon, 9327c478bd9Sstevel@tonic-gate kaif_modchg_register, 9337c478bd9Sstevel@tonic-gate kaif_modchg_cancel, 9347c478bd9Sstevel@tonic-gate kaif_get_cpu_state, 9357c478bd9Sstevel@tonic-gate kaif_get_master_cpuid, 9367c478bd9Sstevel@tonic-gate kaif_get_gregs, 937*acbc304dSjohnlev kaif_get_register, 938*acbc304dSjohnlev kaif_set_register, 9397c478bd9Sstevel@tonic-gate kaif_brkpt_arm, 9407c478bd9Sstevel@tonic-gate kaif_brkpt_disarm, 9417c478bd9Sstevel@tonic-gate kaif_wapt_validate, 9427c478bd9Sstevel@tonic-gate kaif_wapt_reserve, 9437c478bd9Sstevel@tonic-gate kaif_wapt_release, 9447c478bd9Sstevel@tonic-gate kaif_wapt_arm, 9457c478bd9Sstevel@tonic-gate kaif_wapt_disarm, 9467c478bd9Sstevel@tonic-gate kaif_wapt_match, 9477c478bd9Sstevel@tonic-gate kaif_step, 9487c478bd9Sstevel@tonic-gate kaif_step_branch, 9497c478bd9Sstevel@tonic-gate kaif_call, 9507c478bd9Sstevel@tonic-gate kaif_dump_crumbs, 9517c478bd9Sstevel@tonic-gate kaif_memrange_add, 9527c478bd9Sstevel@tonic-gate kaif_msr_add, 9537c478bd9Sstevel@tonic-gate kaif_msr_get, 9547c478bd9Sstevel@tonic-gate }; 955