1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * The debugger/"PROM" interface layer 31*7c478bd9Sstevel@tonic-gate * 32*7c478bd9Sstevel@tonic-gate * (it makes more sense on SPARC) 33*7c478bd9Sstevel@tonic-gate */ 34*7c478bd9Sstevel@tonic-gate 35*7c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_dpi_impl.h> 36*7c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_kdi.h> 37*7c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_umemglue.h> 38*7c478bd9Sstevel@tonic-gate #include <kmdb/kaif.h> 39*7c478bd9Sstevel@tonic-gate #include <kmdb/kaif_asmutil.h> 40*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_err.h> 41*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_debug.h> 42*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_isautil.h> 43*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_io_impl.h> 44*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_kreg.h> 45*7c478bd9Sstevel@tonic-gate #include <mdb/mdb.h> 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/segments.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/bitmap.h> 50*7c478bd9Sstevel@tonic-gate 51*7c478bd9Sstevel@tonic-gate kaif_cpusave_t *kaif_cpusave; 52*7c478bd9Sstevel@tonic-gate int kaif_ncpusave; 53*7c478bd9Sstevel@tonic-gate 54*7c478bd9Sstevel@tonic-gate kaif_drreg_t kaif_drreg; 55*7c478bd9Sstevel@tonic-gate 56*7c478bd9Sstevel@tonic-gate uint32_t kaif_waptmap; 57*7c478bd9Sstevel@tonic-gate 58*7c478bd9Sstevel@tonic-gate #ifndef __amd64 59*7c478bd9Sstevel@tonic-gate /* Used to track the current set of valid kernel selectors. */ 60*7c478bd9Sstevel@tonic-gate uint32_t kaif_cs; 61*7c478bd9Sstevel@tonic-gate uint32_t kaif_ds; 62*7c478bd9Sstevel@tonic-gate uint32_t kaif_fs; 63*7c478bd9Sstevel@tonic-gate uint32_t kaif_gs; 64*7c478bd9Sstevel@tonic-gate #endif 65*7c478bd9Sstevel@tonic-gate 66*7c478bd9Sstevel@tonic-gate uint_t kaif_msr_wrexit_msr; 67*7c478bd9Sstevel@tonic-gate uint64_t *kaif_msr_wrexit_valp; 68*7c478bd9Sstevel@tonic-gate 69*7c478bd9Sstevel@tonic-gate uintptr_t kaif_kernel_handler; 70*7c478bd9Sstevel@tonic-gate uintptr_t kaif_sys_sysenter; 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate int kaif_trap_switch; 73*7c478bd9Sstevel@tonic-gate 74*7c478bd9Sstevel@tonic-gate void (*kaif_modchg_cb)(struct modctl *, int); 75*7c478bd9Sstevel@tonic-gate 76*7c478bd9Sstevel@tonic-gate #define KAIF_MEMRANGES_MAX 2 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate kaif_memrange_t kaif_memranges[KAIF_MEMRANGES_MAX]; 79*7c478bd9Sstevel@tonic-gate int kaif_nmemranges; 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate enum { 82*7c478bd9Sstevel@tonic-gate M_SYSRET = 0x07, /* after M_ESC */ 83*7c478bd9Sstevel@tonic-gate M_ESC = 0x0f, 84*7c478bd9Sstevel@tonic-gate M_SYSEXIT = 0x35, /* after M_ESC */ 85*7c478bd9Sstevel@tonic-gate M_REX_LO = 0x40, /* first REX prefix */ 86*7c478bd9Sstevel@tonic-gate M_REX_HI = 0x4f, /* last REX prefix */ 87*7c478bd9Sstevel@tonic-gate M_PUSHF = 0x9c, /* pushfl and pushfq */ 88*7c478bd9Sstevel@tonic-gate M_POPF = 0x9d, /* popfl and popfq */ 89*7c478bd9Sstevel@tonic-gate M_INT3 = 0xcc, 90*7c478bd9Sstevel@tonic-gate M_INTX = 0xcd, 91*7c478bd9Sstevel@tonic-gate M_INTO = 0xce, 92*7c478bd9Sstevel@tonic-gate M_IRET = 0xcf, 93*7c478bd9Sstevel@tonic-gate M_CLI = 0xfa, 94*7c478bd9Sstevel@tonic-gate M_STI = 0xfb 95*7c478bd9Sstevel@tonic-gate }; 96*7c478bd9Sstevel@tonic-gate 97*7c478bd9Sstevel@tonic-gate #define KAIF_BREAKPOINT_INSTR M_INT3 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate #define KAIF_WPPRIV2ID(wp) (int)(uintptr_t)((wp)->wp_priv) 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate #ifdef __amd64 102*7c478bd9Sstevel@tonic-gate #define FLAGS_REG_NAME "rflags" 103*7c478bd9Sstevel@tonic-gate #else 104*7c478bd9Sstevel@tonic-gate #define FLAGS_REG_NAME "eflags" 105*7c478bd9Sstevel@tonic-gate #endif 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate /* 108*7c478bd9Sstevel@tonic-gate * Called during normal debugger operation and during debugger faults. 109*7c478bd9Sstevel@tonic-gate */ 110*7c478bd9Sstevel@tonic-gate static void 111*7c478bd9Sstevel@tonic-gate kaif_enter_mon(void) 112*7c478bd9Sstevel@tonic-gate { 113*7c478bd9Sstevel@tonic-gate char c; 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate for (;;) { 116*7c478bd9Sstevel@tonic-gate mdb_iob_printf(mdb.m_out, 117*7c478bd9Sstevel@tonic-gate "%s: Do you really want to reboot? (y/n) ", 118*7c478bd9Sstevel@tonic-gate mdb.m_pname); 119*7c478bd9Sstevel@tonic-gate mdb_iob_flush(mdb.m_out); 120*7c478bd9Sstevel@tonic-gate 121*7c478bd9Sstevel@tonic-gate while (IOP_READ(mdb.m_term, &c, 1) != 1) 122*7c478bd9Sstevel@tonic-gate continue; 123*7c478bd9Sstevel@tonic-gate mdb_iob_printf(mdb.m_out, "%c%s", c, (c == '\n' ? "" : "\n")); 124*7c478bd9Sstevel@tonic-gate 125*7c478bd9Sstevel@tonic-gate if (c == 'n' || c == 'N') 126*7c478bd9Sstevel@tonic-gate return; 127*7c478bd9Sstevel@tonic-gate else if (c == 'y' || c == 'Y') { 128*7c478bd9Sstevel@tonic-gate mdb_iob_printf(mdb.m_out, "Rebooting...\n"); 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate kmdb_dpi_reboot(); 131*7c478bd9Sstevel@tonic-gate } 132*7c478bd9Sstevel@tonic-gate } 133*7c478bd9Sstevel@tonic-gate } 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate static int 136*7c478bd9Sstevel@tonic-gate kaif_get_cpu_state(int cpuid) 137*7c478bd9Sstevel@tonic-gate { 138*7c478bd9Sstevel@tonic-gate if (cpuid == DPI_MASTER_CPUID) 139*7c478bd9Sstevel@tonic-gate return (DPI_CPU_STATE_MASTER); 140*7c478bd9Sstevel@tonic-gate 141*7c478bd9Sstevel@tonic-gate if (cpuid < 0 || cpuid >= kaif_ncpusave) 142*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 143*7c478bd9Sstevel@tonic-gate 144*7c478bd9Sstevel@tonic-gate switch (kaif_cpusave[cpuid].krs_cpu_state) { 145*7c478bd9Sstevel@tonic-gate case KAIF_CPU_STATE_MASTER: 146*7c478bd9Sstevel@tonic-gate return (DPI_CPU_STATE_MASTER); 147*7c478bd9Sstevel@tonic-gate case KAIF_CPU_STATE_SLAVE: 148*7c478bd9Sstevel@tonic-gate return (DPI_CPU_STATE_SLAVE); 149*7c478bd9Sstevel@tonic-gate default: 150*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 151*7c478bd9Sstevel@tonic-gate } 152*7c478bd9Sstevel@tonic-gate } 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate static int 155*7c478bd9Sstevel@tonic-gate kaif_get_master_cpuid(void) 156*7c478bd9Sstevel@tonic-gate { 157*7c478bd9Sstevel@tonic-gate return (kaif_master_cpuid); 158*7c478bd9Sstevel@tonic-gate } 159*7c478bd9Sstevel@tonic-gate 160*7c478bd9Sstevel@tonic-gate static const mdb_tgt_gregset_t * 161*7c478bd9Sstevel@tonic-gate kaif_get_gregs(int cpuid) 162*7c478bd9Sstevel@tonic-gate { 163*7c478bd9Sstevel@tonic-gate if (cpuid == DPI_MASTER_CPUID) 164*7c478bd9Sstevel@tonic-gate cpuid = kaif_master_cpuid; 165*7c478bd9Sstevel@tonic-gate 166*7c478bd9Sstevel@tonic-gate if (cpuid < 0 || cpuid >= kaif_ncpusave) { 167*7c478bd9Sstevel@tonic-gate (void) set_errno(EINVAL); 168*7c478bd9Sstevel@tonic-gate return (NULL); 169*7c478bd9Sstevel@tonic-gate } 170*7c478bd9Sstevel@tonic-gate 171*7c478bd9Sstevel@tonic-gate return (kaif_cpusave[cpuid].krs_gregs); 172*7c478bd9Sstevel@tonic-gate } 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate typedef struct kaif_reg_synonyms { 175*7c478bd9Sstevel@tonic-gate const char *rs_syn; 176*7c478bd9Sstevel@tonic-gate const char *rs_name; 177*7c478bd9Sstevel@tonic-gate } kaif_reg_synonyms_t; 178*7c478bd9Sstevel@tonic-gate 179*7c478bd9Sstevel@tonic-gate static kreg_t * 180*7c478bd9Sstevel@tonic-gate kaif_find_regp(int cpuid, const char *regname) 181*7c478bd9Sstevel@tonic-gate { 182*7c478bd9Sstevel@tonic-gate static const kaif_reg_synonyms_t synonyms[] = { 183*7c478bd9Sstevel@tonic-gate #ifdef __amd64 184*7c478bd9Sstevel@tonic-gate { "pc", "rip" }, 185*7c478bd9Sstevel@tonic-gate { "sp", "rsp" }, 186*7c478bd9Sstevel@tonic-gate { "fp", "rbp" }, 187*7c478bd9Sstevel@tonic-gate #else 188*7c478bd9Sstevel@tonic-gate { "pc", "eip" }, 189*7c478bd9Sstevel@tonic-gate { "sp", "esp" }, 190*7c478bd9Sstevel@tonic-gate { "fp", "ebp" }, 191*7c478bd9Sstevel@tonic-gate #endif 192*7c478bd9Sstevel@tonic-gate { "tt", "trapno" } 193*7c478bd9Sstevel@tonic-gate }; 194*7c478bd9Sstevel@tonic-gate int i; 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate if (cpuid == DPI_MASTER_CPUID) 197*7c478bd9Sstevel@tonic-gate cpuid = kaif_master_cpuid; 198*7c478bd9Sstevel@tonic-gate 199*7c478bd9Sstevel@tonic-gate if (cpuid < 0 || cpuid >= kaif_ncpusave) { 200*7c478bd9Sstevel@tonic-gate (void) set_errno(EINVAL); 201*7c478bd9Sstevel@tonic-gate return (NULL); 202*7c478bd9Sstevel@tonic-gate } 203*7c478bd9Sstevel@tonic-gate 204*7c478bd9Sstevel@tonic-gate for (i = 0; i < sizeof (synonyms) / sizeof (synonyms[0]); i++) { 205*7c478bd9Sstevel@tonic-gate if (strcmp(synonyms[i].rs_syn, regname) == 0) 206*7c478bd9Sstevel@tonic-gate regname = synonyms[i].rs_name; 207*7c478bd9Sstevel@tonic-gate } 208*7c478bd9Sstevel@tonic-gate 209*7c478bd9Sstevel@tonic-gate for (i = 0; mdb_isa_kregs[i].rd_name != NULL; i++) { 210*7c478bd9Sstevel@tonic-gate const mdb_tgt_regdesc_t *rd = &mdb_isa_kregs[i]; 211*7c478bd9Sstevel@tonic-gate 212*7c478bd9Sstevel@tonic-gate if (strcmp(rd->rd_name, regname) == 0) 213*7c478bd9Sstevel@tonic-gate return (&kaif_cpusave[cpuid].krs_gregs-> 214*7c478bd9Sstevel@tonic-gate kregs[rd->rd_num]); 215*7c478bd9Sstevel@tonic-gate } 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate (void) set_errno(ENOENT); 218*7c478bd9Sstevel@tonic-gate return (NULL); 219*7c478bd9Sstevel@tonic-gate } 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 222*7c478bd9Sstevel@tonic-gate static int 223*7c478bd9Sstevel@tonic-gate kaif_get_cpu_register(int cpuid, const char *regname, kreg_t *valp) 224*7c478bd9Sstevel@tonic-gate { 225*7c478bd9Sstevel@tonic-gate kreg_t *regp; 226*7c478bd9Sstevel@tonic-gate 227*7c478bd9Sstevel@tonic-gate if ((regp = kaif_find_regp(cpuid, regname)) == NULL) 228*7c478bd9Sstevel@tonic-gate return (-1); 229*7c478bd9Sstevel@tonic-gate 230*7c478bd9Sstevel@tonic-gate *valp = *regp; 231*7c478bd9Sstevel@tonic-gate 232*7c478bd9Sstevel@tonic-gate return (0); 233*7c478bd9Sstevel@tonic-gate } 234*7c478bd9Sstevel@tonic-gate 235*7c478bd9Sstevel@tonic-gate static int 236*7c478bd9Sstevel@tonic-gate kaif_set_cpu_register(int cpuid, const char *regname, kreg_t val) 237*7c478bd9Sstevel@tonic-gate { 238*7c478bd9Sstevel@tonic-gate kreg_t *regp; 239*7c478bd9Sstevel@tonic-gate 240*7c478bd9Sstevel@tonic-gate if ((regp = kaif_find_regp(cpuid, regname)) == NULL) 241*7c478bd9Sstevel@tonic-gate return (-1); 242*7c478bd9Sstevel@tonic-gate 243*7c478bd9Sstevel@tonic-gate *regp = val; 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate return (0); 246*7c478bd9Sstevel@tonic-gate } 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate static int 249*7c478bd9Sstevel@tonic-gate kaif_brkpt_arm(uintptr_t addr, mdb_instr_t *instrp) 250*7c478bd9Sstevel@tonic-gate { 251*7c478bd9Sstevel@tonic-gate mdb_instr_t bkpt = KAIF_BREAKPOINT_INSTR; 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate if (mdb_tgt_vread(mdb.m_target, instrp, sizeof (mdb_instr_t), addr) != 254*7c478bd9Sstevel@tonic-gate sizeof (mdb_instr_t)) 255*7c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 256*7c478bd9Sstevel@tonic-gate 257*7c478bd9Sstevel@tonic-gate if (mdb_tgt_vwrite(mdb.m_target, &bkpt, sizeof (mdb_instr_t), addr) != 258*7c478bd9Sstevel@tonic-gate sizeof (mdb_instr_t)) 259*7c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 260*7c478bd9Sstevel@tonic-gate 261*7c478bd9Sstevel@tonic-gate return (0); 262*7c478bd9Sstevel@tonic-gate } 263*7c478bd9Sstevel@tonic-gate 264*7c478bd9Sstevel@tonic-gate static int 265*7c478bd9Sstevel@tonic-gate kaif_brkpt_disarm(uintptr_t addr, mdb_instr_t instrp) 266*7c478bd9Sstevel@tonic-gate { 267*7c478bd9Sstevel@tonic-gate if (mdb_tgt_vwrite(mdb.m_target, &instrp, sizeof (mdb_instr_t), addr) != 268*7c478bd9Sstevel@tonic-gate sizeof (mdb_instr_t)) 269*7c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 270*7c478bd9Sstevel@tonic-gate 271*7c478bd9Sstevel@tonic-gate return (0); 272*7c478bd9Sstevel@tonic-gate } 273*7c478bd9Sstevel@tonic-gate 274*7c478bd9Sstevel@tonic-gate /* 275*7c478bd9Sstevel@tonic-gate * Intel watchpoints are even more fun than SPARC ones. The Intel architecture 276*7c478bd9Sstevel@tonic-gate * manuals refer to watchpoints as breakpoints. For consistency with the 277*7c478bd9Sstevel@tonic-gate * terminology used in other portions of kmdb, we will, however, refer to them 278*7c478bd9Sstevel@tonic-gate * as watchpoints. 279*7c478bd9Sstevel@tonic-gate * 280*7c478bd9Sstevel@tonic-gate * Execute, data write, I/O read/write, and data read/write watchpoints are 281*7c478bd9Sstevel@tonic-gate * supported by the hardware. Execute watchpoints must be one byte in length, 282*7c478bd9Sstevel@tonic-gate * and must be placed on the first byte of the instruction to be watched. 283*7c478bd9Sstevel@tonic-gate * Lengths of other watchpoints are more varied. 284*7c478bd9Sstevel@tonic-gate * 285*7c478bd9Sstevel@tonic-gate * Given that we already have a breakpoint facility, and given the restrictions 286*7c478bd9Sstevel@tonic-gate * placed on execute watchpoints, we're going to disallow the creation of 287*7c478bd9Sstevel@tonic-gate * execute watchpoints. The others will be fully supported. See the Debugging 288*7c478bd9Sstevel@tonic-gate * chapter in both the IA32 and AMD64 System Programming books for more details. 289*7c478bd9Sstevel@tonic-gate */ 290*7c478bd9Sstevel@tonic-gate 291*7c478bd9Sstevel@tonic-gate #ifdef __amd64 292*7c478bd9Sstevel@tonic-gate #define WAPT_DATA_MAX_SIZE 8 293*7c478bd9Sstevel@tonic-gate #define WAPT_DATA_SIZES_MSG "1, 2, 4, or 8" 294*7c478bd9Sstevel@tonic-gate #else 295*7c478bd9Sstevel@tonic-gate #define WAPT_DATA_MAX_SIZE 4 296*7c478bd9Sstevel@tonic-gate #define WAPT_DATA_SIZES_MSG "1, 2, or 4" 297*7c478bd9Sstevel@tonic-gate #endif 298*7c478bd9Sstevel@tonic-gate 299*7c478bd9Sstevel@tonic-gate static int 300*7c478bd9Sstevel@tonic-gate kaif_wapt_validate(kmdb_wapt_t *wp) 301*7c478bd9Sstevel@tonic-gate { 302*7c478bd9Sstevel@tonic-gate if (wp->wp_type == DPI_WAPT_TYPE_IO) { 303*7c478bd9Sstevel@tonic-gate if (wp->wp_wflags != (MDB_TGT_WA_R | MDB_TGT_WA_W)) { 304*7c478bd9Sstevel@tonic-gate warn("I/O port watchpoints must be read/write\n"); 305*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 306*7c478bd9Sstevel@tonic-gate } 307*7c478bd9Sstevel@tonic-gate 308*7c478bd9Sstevel@tonic-gate if (wp->wp_size != 1 && wp->wp_size != 2 && wp->wp_size != 4) { 309*7c478bd9Sstevel@tonic-gate warn("I/O watchpoint size must be 1, 2, or 4 bytes\n"); 310*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 311*7c478bd9Sstevel@tonic-gate } 312*7c478bd9Sstevel@tonic-gate 313*7c478bd9Sstevel@tonic-gate } else if (wp->wp_type == DPI_WAPT_TYPE_PHYS) { 314*7c478bd9Sstevel@tonic-gate warn("physical address watchpoints are not supported on this " 315*7c478bd9Sstevel@tonic-gate "platform\n"); 316*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGTHWNOTSUP)); 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate } else { 319*7c478bd9Sstevel@tonic-gate if (wp->wp_wflags != (MDB_TGT_WA_R | MDB_TGT_WA_W) && 320*7c478bd9Sstevel@tonic-gate wp->wp_wflags != MDB_TGT_WA_W) { 321*7c478bd9Sstevel@tonic-gate warn("watchpoints must be read/write or write-only\n"); 322*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 323*7c478bd9Sstevel@tonic-gate } 324*7c478bd9Sstevel@tonic-gate 325*7c478bd9Sstevel@tonic-gate if ((wp->wp_size & -(wp->wp_size)) != wp->wp_size || 326*7c478bd9Sstevel@tonic-gate wp->wp_size > WAPT_DATA_MAX_SIZE) { 327*7c478bd9Sstevel@tonic-gate warn("data watchpoint size must be " WAPT_DATA_SIZES_MSG 328*7c478bd9Sstevel@tonic-gate " bytes\n"); 329*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 330*7c478bd9Sstevel@tonic-gate } 331*7c478bd9Sstevel@tonic-gate 332*7c478bd9Sstevel@tonic-gate } 333*7c478bd9Sstevel@tonic-gate 334*7c478bd9Sstevel@tonic-gate if (wp->wp_addr & (wp->wp_size - 1)) { 335*7c478bd9Sstevel@tonic-gate warn("%lu-byte watchpoints must be %lu-byte aligned\n", 336*7c478bd9Sstevel@tonic-gate (ulong_t)wp->wp_size, (ulong_t)wp->wp_size); 337*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 338*7c478bd9Sstevel@tonic-gate } 339*7c478bd9Sstevel@tonic-gate 340*7c478bd9Sstevel@tonic-gate return (0); 341*7c478bd9Sstevel@tonic-gate } 342*7c478bd9Sstevel@tonic-gate 343*7c478bd9Sstevel@tonic-gate static int 344*7c478bd9Sstevel@tonic-gate kaif_wapt_reserve(kmdb_wapt_t *wp) 345*7c478bd9Sstevel@tonic-gate { 346*7c478bd9Sstevel@tonic-gate int id; 347*7c478bd9Sstevel@tonic-gate 348*7c478bd9Sstevel@tonic-gate for (id = 0; id <= KREG_MAXWPIDX; id++) { 349*7c478bd9Sstevel@tonic-gate if (!BT_TEST(&kaif_waptmap, id)) { 350*7c478bd9Sstevel@tonic-gate /* found one */ 351*7c478bd9Sstevel@tonic-gate BT_SET(&kaif_waptmap, id); 352*7c478bd9Sstevel@tonic-gate wp->wp_priv = (void *)(uintptr_t)id; 353*7c478bd9Sstevel@tonic-gate return (0); 354*7c478bd9Sstevel@tonic-gate } 355*7c478bd9Sstevel@tonic-gate } 356*7c478bd9Sstevel@tonic-gate 357*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_WPTOOMANY)); 358*7c478bd9Sstevel@tonic-gate } 359*7c478bd9Sstevel@tonic-gate 360*7c478bd9Sstevel@tonic-gate static void 361*7c478bd9Sstevel@tonic-gate kaif_wapt_release(kmdb_wapt_t *wp) 362*7c478bd9Sstevel@tonic-gate { 363*7c478bd9Sstevel@tonic-gate int id = KAIF_WPPRIV2ID(wp); 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate ASSERT(BT_TEST(&kaif_waptmap, id)); 366*7c478bd9Sstevel@tonic-gate BT_CLEAR(&kaif_waptmap, id); 367*7c478bd9Sstevel@tonic-gate } 368*7c478bd9Sstevel@tonic-gate 369*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 370*7c478bd9Sstevel@tonic-gate static void 371*7c478bd9Sstevel@tonic-gate kaif_wapt_arm(kmdb_wapt_t *wp) 372*7c478bd9Sstevel@tonic-gate { 373*7c478bd9Sstevel@tonic-gate uint_t rw; 374*7c478bd9Sstevel@tonic-gate int hwid = KAIF_WPPRIV2ID(wp); 375*7c478bd9Sstevel@tonic-gate 376*7c478bd9Sstevel@tonic-gate ASSERT(BT_TEST(&kaif_waptmap, hwid)); 377*7c478bd9Sstevel@tonic-gate 378*7c478bd9Sstevel@tonic-gate if (wp->wp_type == DPI_WAPT_TYPE_IO) 379*7c478bd9Sstevel@tonic-gate rw = KREG_DRCTL_WP_IORW; 380*7c478bd9Sstevel@tonic-gate else if (wp->wp_wflags & MDB_TGT_WA_R) 381*7c478bd9Sstevel@tonic-gate rw = KREG_DRCTL_WP_RW; 382*7c478bd9Sstevel@tonic-gate else if (wp->wp_wflags & MDB_TGT_WA_X) 383*7c478bd9Sstevel@tonic-gate rw = KREG_DRCTL_WP_EXEC; 384*7c478bd9Sstevel@tonic-gate else 385*7c478bd9Sstevel@tonic-gate rw = KREG_DRCTL_WP_WONLY; 386*7c478bd9Sstevel@tonic-gate 387*7c478bd9Sstevel@tonic-gate kaif_drreg.dr_addr[hwid] = wp->wp_addr; 388*7c478bd9Sstevel@tonic-gate 389*7c478bd9Sstevel@tonic-gate kaif_drreg.dr_ctl &= ~KREG_DRCTL_WP_MASK(hwid); 390*7c478bd9Sstevel@tonic-gate kaif_drreg.dr_ctl |= KREG_DRCTL_WP_LENRW(hwid, wp->wp_size - 1, rw); 391*7c478bd9Sstevel@tonic-gate kaif_drreg.dr_ctl |= KREG_DRCTL_WPEN(hwid); 392*7c478bd9Sstevel@tonic-gate } 393*7c478bd9Sstevel@tonic-gate 394*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 395*7c478bd9Sstevel@tonic-gate static void 396*7c478bd9Sstevel@tonic-gate kaif_wapt_disarm(kmdb_wapt_t *wp) 397*7c478bd9Sstevel@tonic-gate { 398*7c478bd9Sstevel@tonic-gate int hwid = KAIF_WPPRIV2ID(wp); 399*7c478bd9Sstevel@tonic-gate 400*7c478bd9Sstevel@tonic-gate ASSERT(BT_TEST(&kaif_waptmap, hwid)); 401*7c478bd9Sstevel@tonic-gate 402*7c478bd9Sstevel@tonic-gate kaif_drreg.dr_addr[hwid] = 0; 403*7c478bd9Sstevel@tonic-gate kaif_drreg.dr_ctl &= ~(KREG_DRCTL_WP_MASK(hwid) | 404*7c478bd9Sstevel@tonic-gate KREG_DRCTL_WPEN_MASK(hwid)); 405*7c478bd9Sstevel@tonic-gate } 406*7c478bd9Sstevel@tonic-gate 407*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 408*7c478bd9Sstevel@tonic-gate static int 409*7c478bd9Sstevel@tonic-gate kaif_wapt_match(kmdb_wapt_t *wp) 410*7c478bd9Sstevel@tonic-gate { 411*7c478bd9Sstevel@tonic-gate int hwid = KAIF_WPPRIV2ID(wp); 412*7c478bd9Sstevel@tonic-gate uint32_t mask = KREG_DRSTAT_WP_MASK(hwid); 413*7c478bd9Sstevel@tonic-gate int n = 0; 414*7c478bd9Sstevel@tonic-gate int i; 415*7c478bd9Sstevel@tonic-gate 416*7c478bd9Sstevel@tonic-gate ASSERT(BT_TEST(&kaif_waptmap, hwid)); 417*7c478bd9Sstevel@tonic-gate 418*7c478bd9Sstevel@tonic-gate for (i = 0; i < kaif_ncpusave; i++) 419*7c478bd9Sstevel@tonic-gate n += (kaif_cpusave[i].krs_dr.dr_stat & mask) != 0; 420*7c478bd9Sstevel@tonic-gate 421*7c478bd9Sstevel@tonic-gate return (n); 422*7c478bd9Sstevel@tonic-gate } 423*7c478bd9Sstevel@tonic-gate 424*7c478bd9Sstevel@tonic-gate static int 425*7c478bd9Sstevel@tonic-gate kaif_step(void) 426*7c478bd9Sstevel@tonic-gate { 427*7c478bd9Sstevel@tonic-gate kreg_t pc, fl, oldfl, newfl, sp; 428*7c478bd9Sstevel@tonic-gate mdb_tgt_addr_t npc; 429*7c478bd9Sstevel@tonic-gate mdb_instr_t instr; 430*7c478bd9Sstevel@tonic-gate int emulated = 0, rchk = 0; 431*7c478bd9Sstevel@tonic-gate size_t pcoff = 0; 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register("pc", &pc); 434*7c478bd9Sstevel@tonic-gate 435*7c478bd9Sstevel@tonic-gate if ((npc = mdb_dis_nextins(mdb.m_disasm, mdb.m_target, 436*7c478bd9Sstevel@tonic-gate MDB_TGT_AS_VIRT, pc)) == pc) { 437*7c478bd9Sstevel@tonic-gate warn("failed to decode instruction at %a for step\n", pc); 438*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 439*7c478bd9Sstevel@tonic-gate } 440*7c478bd9Sstevel@tonic-gate 441*7c478bd9Sstevel@tonic-gate /* 442*7c478bd9Sstevel@tonic-gate * Stepping behavior depends on the type of instruction. It does not 443*7c478bd9Sstevel@tonic-gate * depend on the presence of a REX prefix, as the action we take for a 444*7c478bd9Sstevel@tonic-gate * given instruction doesn't currently vary for 32-bit instructions 445*7c478bd9Sstevel@tonic-gate * versus their 64-bit counterparts. 446*7c478bd9Sstevel@tonic-gate */ 447*7c478bd9Sstevel@tonic-gate do { 448*7c478bd9Sstevel@tonic-gate if (mdb_tgt_vread(mdb.m_target, &instr, sizeof (mdb_instr_t), 449*7c478bd9Sstevel@tonic-gate pc + pcoff) != sizeof (mdb_instr_t)) { 450*7c478bd9Sstevel@tonic-gate warn("failed to read at %p for step", 451*7c478bd9Sstevel@tonic-gate (void *)(pc + pcoff)); 452*7c478bd9Sstevel@tonic-gate return (-1); 453*7c478bd9Sstevel@tonic-gate } 454*7c478bd9Sstevel@tonic-gate } while (pcoff++, (instr >= M_REX_LO && instr <= M_REX_HI && !rchk++)); 455*7c478bd9Sstevel@tonic-gate 456*7c478bd9Sstevel@tonic-gate switch (instr) { 457*7c478bd9Sstevel@tonic-gate case M_IRET: 458*7c478bd9Sstevel@tonic-gate warn("iret cannot be stepped\n"); 459*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP)); 460*7c478bd9Sstevel@tonic-gate 461*7c478bd9Sstevel@tonic-gate case M_INT3: 462*7c478bd9Sstevel@tonic-gate case M_INTX: 463*7c478bd9Sstevel@tonic-gate case M_INTO: 464*7c478bd9Sstevel@tonic-gate warn("int cannot be stepped\n"); 465*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP)); 466*7c478bd9Sstevel@tonic-gate 467*7c478bd9Sstevel@tonic-gate case M_ESC: 468*7c478bd9Sstevel@tonic-gate if (mdb_tgt_vread(mdb.m_target, &instr, sizeof (mdb_instr_t), 469*7c478bd9Sstevel@tonic-gate pc + pcoff) != sizeof (mdb_instr_t)) { 470*7c478bd9Sstevel@tonic-gate warn("failed to read at %p for step", 471*7c478bd9Sstevel@tonic-gate (void *)(pc + pcoff)); 472*7c478bd9Sstevel@tonic-gate return (-1); 473*7c478bd9Sstevel@tonic-gate } 474*7c478bd9Sstevel@tonic-gate 475*7c478bd9Sstevel@tonic-gate switch (instr) { 476*7c478bd9Sstevel@tonic-gate case M_SYSRET: 477*7c478bd9Sstevel@tonic-gate warn("sysret cannot be stepped\n"); 478*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP)); 479*7c478bd9Sstevel@tonic-gate case M_SYSEXIT: 480*7c478bd9Sstevel@tonic-gate warn("sysexit cannot be stepped\n"); 481*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP)); 482*7c478bd9Sstevel@tonic-gate } 483*7c478bd9Sstevel@tonic-gate break; 484*7c478bd9Sstevel@tonic-gate 485*7c478bd9Sstevel@tonic-gate /* 486*7c478bd9Sstevel@tonic-gate * Some instructions need to be emulated. We need to prevent direct 487*7c478bd9Sstevel@tonic-gate * manipulations of EFLAGS, so we'll emulate cli, sti. pushfl and 488*7c478bd9Sstevel@tonic-gate * popfl also receive special handling, as they manipulate both EFLAGS 489*7c478bd9Sstevel@tonic-gate * and %esp. 490*7c478bd9Sstevel@tonic-gate */ 491*7c478bd9Sstevel@tonic-gate case M_CLI: 492*7c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl); 493*7c478bd9Sstevel@tonic-gate fl &= ~KREG_EFLAGS_IF_MASK; 494*7c478bd9Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, fl); 495*7c478bd9Sstevel@tonic-gate 496*7c478bd9Sstevel@tonic-gate emulated = 1; 497*7c478bd9Sstevel@tonic-gate break; 498*7c478bd9Sstevel@tonic-gate 499*7c478bd9Sstevel@tonic-gate case M_STI: 500*7c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl); 501*7c478bd9Sstevel@tonic-gate fl |= (1 << KREG_EFLAGS_IF_SHIFT); 502*7c478bd9Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, fl); 503*7c478bd9Sstevel@tonic-gate 504*7c478bd9Sstevel@tonic-gate emulated = 1; 505*7c478bd9Sstevel@tonic-gate break; 506*7c478bd9Sstevel@tonic-gate 507*7c478bd9Sstevel@tonic-gate case M_POPF: 508*7c478bd9Sstevel@tonic-gate /* 509*7c478bd9Sstevel@tonic-gate * popfl will restore a pushed EFLAGS from the stack, and could 510*7c478bd9Sstevel@tonic-gate * in so doing cause IF to be turned on, if only for a a brief 511*7c478bd9Sstevel@tonic-gate * period. To avoid this, we'll secretly replace the stack's 512*7c478bd9Sstevel@tonic-gate * EFLAGS with our decaffeinated brand. We'll then manually 513*7c478bd9Sstevel@tonic-gate * load our EFLAGS copy with the real verion after the step. 514*7c478bd9Sstevel@tonic-gate */ 515*7c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register("sp", &sp); 516*7c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl); 517*7c478bd9Sstevel@tonic-gate 518*7c478bd9Sstevel@tonic-gate if (mdb_tgt_vread(mdb.m_target, &newfl, sizeof (kreg_t), 519*7c478bd9Sstevel@tonic-gate sp) != sizeof (kreg_t)) { 520*7c478bd9Sstevel@tonic-gate warn("failed to read " FLAGS_REG_NAME 521*7c478bd9Sstevel@tonic-gate " at %p for popfl step\n", (void *)sp); 522*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */ 523*7c478bd9Sstevel@tonic-gate } 524*7c478bd9Sstevel@tonic-gate 525*7c478bd9Sstevel@tonic-gate fl = (fl & ~KREG_EFLAGS_IF_MASK) | KREG_EFLAGS_TF_MASK; 526*7c478bd9Sstevel@tonic-gate 527*7c478bd9Sstevel@tonic-gate if (mdb_tgt_vwrite(mdb.m_target, &fl, sizeof (kreg_t), 528*7c478bd9Sstevel@tonic-gate sp) != sizeof (kreg_t)) { 529*7c478bd9Sstevel@tonic-gate warn("failed to update " FLAGS_REG_NAME 530*7c478bd9Sstevel@tonic-gate " at %p for popfl step\n", (void *)sp); 531*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */ 532*7c478bd9Sstevel@tonic-gate } 533*7c478bd9Sstevel@tonic-gate break; 534*7c478bd9Sstevel@tonic-gate } 535*7c478bd9Sstevel@tonic-gate 536*7c478bd9Sstevel@tonic-gate if (emulated) { 537*7c478bd9Sstevel@tonic-gate (void) kmdb_dpi_set_register("pc", npc); 538*7c478bd9Sstevel@tonic-gate return (0); 539*7c478bd9Sstevel@tonic-gate } 540*7c478bd9Sstevel@tonic-gate 541*7c478bd9Sstevel@tonic-gate /* Do the step with IF off, and TF (step) on */ 542*7c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &oldfl); 543*7c478bd9Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, 544*7c478bd9Sstevel@tonic-gate ((oldfl | (1 << KREG_EFLAGS_TF_SHIFT)) & ~KREG_EFLAGS_IF_MASK)); 545*7c478bd9Sstevel@tonic-gate 546*7c478bd9Sstevel@tonic-gate kmdb_dpi_resume_master(); /* ... there and back again ... */ 547*7c478bd9Sstevel@tonic-gate 548*7c478bd9Sstevel@tonic-gate /* EFLAGS has now changed, and may require tuning */ 549*7c478bd9Sstevel@tonic-gate 550*7c478bd9Sstevel@tonic-gate switch (instr) { 551*7c478bd9Sstevel@tonic-gate case M_POPF: 552*7c478bd9Sstevel@tonic-gate /* 553*7c478bd9Sstevel@tonic-gate * Use the EFLAGS we grabbed before the pop - see the pre-step 554*7c478bd9Sstevel@tonic-gate * M_POPFL comment. 555*7c478bd9Sstevel@tonic-gate */ 556*7c478bd9Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, newfl); 557*7c478bd9Sstevel@tonic-gate return (0); 558*7c478bd9Sstevel@tonic-gate 559*7c478bd9Sstevel@tonic-gate case M_PUSHF: 560*7c478bd9Sstevel@tonic-gate /* 561*7c478bd9Sstevel@tonic-gate * We pushed our modified EFLAGS (with IF and TF turned off) 562*7c478bd9Sstevel@tonic-gate * onto the stack. Replace the pushed version with our 563*7c478bd9Sstevel@tonic-gate * unmodified one. 564*7c478bd9Sstevel@tonic-gate */ 565*7c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register("sp", &sp); 566*7c478bd9Sstevel@tonic-gate 567*7c478bd9Sstevel@tonic-gate if (mdb_tgt_vwrite(mdb.m_target, &oldfl, sizeof (kreg_t), 568*7c478bd9Sstevel@tonic-gate sp) != sizeof (kreg_t)) { 569*7c478bd9Sstevel@tonic-gate warn("failed to update pushed " FLAGS_REG_NAME 570*7c478bd9Sstevel@tonic-gate " at %p after pushfl step\n", (void *)sp); 571*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */ 572*7c478bd9Sstevel@tonic-gate } 573*7c478bd9Sstevel@tonic-gate 574*7c478bd9Sstevel@tonic-gate /* Go back to using the EFLAGS we were using before the step */ 575*7c478bd9Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, oldfl); 576*7c478bd9Sstevel@tonic-gate return (0); 577*7c478bd9Sstevel@tonic-gate 578*7c478bd9Sstevel@tonic-gate default: 579*7c478bd9Sstevel@tonic-gate /* 580*7c478bd9Sstevel@tonic-gate * The stepped instruction may have altered EFLAGS. We only 581*7c478bd9Sstevel@tonic-gate * really care about the value of IF, and we know the stepped 582*7c478bd9Sstevel@tonic-gate * instruction didn't alter it, so we can simply copy the 583*7c478bd9Sstevel@tonic-gate * pre-step value. We'll also need to turn TF back off. 584*7c478bd9Sstevel@tonic-gate */ 585*7c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl); 586*7c478bd9Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, 587*7c478bd9Sstevel@tonic-gate ((fl & ~(KREG_EFLAGS_TF_MASK|KREG_EFLAGS_IF_MASK)) | 588*7c478bd9Sstevel@tonic-gate (oldfl & KREG_EFLAGS_IF_MASK))); 589*7c478bd9Sstevel@tonic-gate return (0); 590*7c478bd9Sstevel@tonic-gate } 591*7c478bd9Sstevel@tonic-gate } 592*7c478bd9Sstevel@tonic-gate 593*7c478bd9Sstevel@tonic-gate /* 594*7c478bd9Sstevel@tonic-gate * The target has already configured the chip for branch step, leaving us to 595*7c478bd9Sstevel@tonic-gate * actually make the machine go. Due to a number of issues involving 596*7c478bd9Sstevel@tonic-gate * the potential alteration of system state via instructions like sti, cli, 597*7c478bd9Sstevel@tonic-gate * pushfl, and popfl, we're going to treat this like a normal system resume. 598*7c478bd9Sstevel@tonic-gate * All CPUs will be released, on the kernel's IDT. Our primary concern is 599*7c478bd9Sstevel@tonic-gate * the alteration/storage of our TF'd EFLAGS via pushfl and popfl. There's no 600*7c478bd9Sstevel@tonic-gate * real workaround - we don't have opcode breakpoints - so the best we can do is 601*7c478bd9Sstevel@tonic-gate * to ensure that the world won't end if someone does bad things to EFLAGS. 602*7c478bd9Sstevel@tonic-gate * 603*7c478bd9Sstevel@tonic-gate * Two things can happen: 604*7c478bd9Sstevel@tonic-gate * 1. EFLAGS.TF may be cleared, either maliciously or via a popfl from saved 605*7c478bd9Sstevel@tonic-gate * state. The CPU will continue execution beyond the branch, and will not 606*7c478bd9Sstevel@tonic-gate * reenter the debugger unless brought/sent in by other means. 607*7c478bd9Sstevel@tonic-gate * 2. Someone may pushlf the TF'd EFLAGS, and may stash a copy of it somewhere. 608*7c478bd9Sstevel@tonic-gate * When the saved version is popfl'd back into place, the debugger will be 609*7c478bd9Sstevel@tonic-gate * re-entered on a single-step trap. 610*7c478bd9Sstevel@tonic-gate */ 611*7c478bd9Sstevel@tonic-gate static void 612*7c478bd9Sstevel@tonic-gate kaif_step_branch(void) 613*7c478bd9Sstevel@tonic-gate { 614*7c478bd9Sstevel@tonic-gate kreg_t fl; 615*7c478bd9Sstevel@tonic-gate 616*7c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl); 617*7c478bd9Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, 618*7c478bd9Sstevel@tonic-gate (fl | (1 << KREG_EFLAGS_TF_SHIFT))); 619*7c478bd9Sstevel@tonic-gate 620*7c478bd9Sstevel@tonic-gate kmdb_dpi_resume_master(); 621*7c478bd9Sstevel@tonic-gate 622*7c478bd9Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, fl); 623*7c478bd9Sstevel@tonic-gate } 624*7c478bd9Sstevel@tonic-gate 625*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 626*7c478bd9Sstevel@tonic-gate static uintptr_t 627*7c478bd9Sstevel@tonic-gate kaif_call(uintptr_t funcva, uint_t argc, const uintptr_t argv[]) 628*7c478bd9Sstevel@tonic-gate { 629*7c478bd9Sstevel@tonic-gate return (kaif_invoke(funcva, argc, argv)); 630*7c478bd9Sstevel@tonic-gate } 631*7c478bd9Sstevel@tonic-gate 632*7c478bd9Sstevel@tonic-gate static void 633*7c478bd9Sstevel@tonic-gate dump_crumb(kaif_crumb_t *crumb) 634*7c478bd9Sstevel@tonic-gate { 635*7c478bd9Sstevel@tonic-gate mdb_printf("state: "); 636*7c478bd9Sstevel@tonic-gate switch (crumb->krm_cpu_state) { 637*7c478bd9Sstevel@tonic-gate case KAIF_CPU_STATE_MASTER: 638*7c478bd9Sstevel@tonic-gate mdb_printf("M"); 639*7c478bd9Sstevel@tonic-gate break; 640*7c478bd9Sstevel@tonic-gate case KAIF_CPU_STATE_SLAVE: 641*7c478bd9Sstevel@tonic-gate mdb_printf("S"); 642*7c478bd9Sstevel@tonic-gate break; 643*7c478bd9Sstevel@tonic-gate default: 644*7c478bd9Sstevel@tonic-gate mdb_printf("%d", crumb->krm_cpu_state); 645*7c478bd9Sstevel@tonic-gate } 646*7c478bd9Sstevel@tonic-gate 647*7c478bd9Sstevel@tonic-gate mdb_printf(" trapno %3d sp %08x flag %d pc %p %A\n", 648*7c478bd9Sstevel@tonic-gate crumb->krm_trapno, crumb->krm_sp, crumb->krm_flag, 649*7c478bd9Sstevel@tonic-gate crumb->krm_pc, crumb->krm_pc); 650*7c478bd9Sstevel@tonic-gate } 651*7c478bd9Sstevel@tonic-gate 652*7c478bd9Sstevel@tonic-gate static void 653*7c478bd9Sstevel@tonic-gate dump_crumbs(kaif_cpusave_t *save) 654*7c478bd9Sstevel@tonic-gate { 655*7c478bd9Sstevel@tonic-gate int i; 656*7c478bd9Sstevel@tonic-gate 657*7c478bd9Sstevel@tonic-gate for (i = KAIF_NCRUMBS; i > 0; i--) { 658*7c478bd9Sstevel@tonic-gate uint_t idx = (save->krs_curcrumbidx + i) % KAIF_NCRUMBS; 659*7c478bd9Sstevel@tonic-gate 660*7c478bd9Sstevel@tonic-gate dump_crumb(&save->krs_crumbs[idx]); 661*7c478bd9Sstevel@tonic-gate } 662*7c478bd9Sstevel@tonic-gate } 663*7c478bd9Sstevel@tonic-gate 664*7c478bd9Sstevel@tonic-gate static void 665*7c478bd9Sstevel@tonic-gate kaif_dump_crumbs(uintptr_t addr, int cpuid) 666*7c478bd9Sstevel@tonic-gate { 667*7c478bd9Sstevel@tonic-gate int i; 668*7c478bd9Sstevel@tonic-gate 669*7c478bd9Sstevel@tonic-gate if (addr != NULL) { 670*7c478bd9Sstevel@tonic-gate dump_crumb((kaif_crumb_t *)addr); 671*7c478bd9Sstevel@tonic-gate 672*7c478bd9Sstevel@tonic-gate } else if (cpuid != -1) { 673*7c478bd9Sstevel@tonic-gate if (cpuid >= kaif_ncpusave) 674*7c478bd9Sstevel@tonic-gate return; 675*7c478bd9Sstevel@tonic-gate 676*7c478bd9Sstevel@tonic-gate dump_crumbs(&kaif_cpusave[cpuid]); 677*7c478bd9Sstevel@tonic-gate 678*7c478bd9Sstevel@tonic-gate } else { 679*7c478bd9Sstevel@tonic-gate for (i = 0; i < kaif_ncpusave; i++) { 680*7c478bd9Sstevel@tonic-gate kaif_cpusave_t *save = &kaif_cpusave[i]; 681*7c478bd9Sstevel@tonic-gate 682*7c478bd9Sstevel@tonic-gate if (save->krs_cpu_state == KAIF_CPU_STATE_NONE) 683*7c478bd9Sstevel@tonic-gate continue; 684*7c478bd9Sstevel@tonic-gate 685*7c478bd9Sstevel@tonic-gate mdb_printf("%sCPU %d crumbs: (curidx %d)\n", 686*7c478bd9Sstevel@tonic-gate (i == 0 ? "" : "\n"), i, save->krs_curcrumbidx); 687*7c478bd9Sstevel@tonic-gate 688*7c478bd9Sstevel@tonic-gate dump_crumbs(save); 689*7c478bd9Sstevel@tonic-gate } 690*7c478bd9Sstevel@tonic-gate } 691*7c478bd9Sstevel@tonic-gate } 692*7c478bd9Sstevel@tonic-gate 693*7c478bd9Sstevel@tonic-gate static void 694*7c478bd9Sstevel@tonic-gate kaif_modchg_register(void (*func)(struct modctl *, int)) 695*7c478bd9Sstevel@tonic-gate { 696*7c478bd9Sstevel@tonic-gate kaif_modchg_cb = func; 697*7c478bd9Sstevel@tonic-gate } 698*7c478bd9Sstevel@tonic-gate 699*7c478bd9Sstevel@tonic-gate static void 700*7c478bd9Sstevel@tonic-gate kaif_modchg_cancel(void) 701*7c478bd9Sstevel@tonic-gate { 702*7c478bd9Sstevel@tonic-gate ASSERT(kaif_modchg_cb != NULL); 703*7c478bd9Sstevel@tonic-gate 704*7c478bd9Sstevel@tonic-gate kaif_modchg_cb = NULL; 705*7c478bd9Sstevel@tonic-gate } 706*7c478bd9Sstevel@tonic-gate 707*7c478bd9Sstevel@tonic-gate void 708*7c478bd9Sstevel@tonic-gate kaif_mod_loaded(struct modctl *modp) 709*7c478bd9Sstevel@tonic-gate { 710*7c478bd9Sstevel@tonic-gate if (kaif_modchg_cb != NULL) 711*7c478bd9Sstevel@tonic-gate kaif_modchg_cb(modp, 1); 712*7c478bd9Sstevel@tonic-gate } 713*7c478bd9Sstevel@tonic-gate 714*7c478bd9Sstevel@tonic-gate void 715*7c478bd9Sstevel@tonic-gate kaif_mod_unloading(struct modctl *modp) 716*7c478bd9Sstevel@tonic-gate { 717*7c478bd9Sstevel@tonic-gate if (kaif_modchg_cb != NULL) 718*7c478bd9Sstevel@tonic-gate kaif_modchg_cb(modp, 0); 719*7c478bd9Sstevel@tonic-gate } 720*7c478bd9Sstevel@tonic-gate 721*7c478bd9Sstevel@tonic-gate /* 722*7c478bd9Sstevel@tonic-gate * On some processors, we'll need to clear a certain MSR before proceeding into 723*7c478bd9Sstevel@tonic-gate * the debugger. Complicating matters, this MSR must be cleared before we take 724*7c478bd9Sstevel@tonic-gate * any branches. We have patch points in every trap handler, which will cover 725*7c478bd9Sstevel@tonic-gate * all entry paths for master CPUs. We also have a patch point in the slave 726*7c478bd9Sstevel@tonic-gate * entry code. 727*7c478bd9Sstevel@tonic-gate */ 728*7c478bd9Sstevel@tonic-gate static void 729*7c478bd9Sstevel@tonic-gate kaif_msr_add_clrentry(uint_t msr) 730*7c478bd9Sstevel@tonic-gate { 731*7c478bd9Sstevel@tonic-gate #ifdef __amd64 732*7c478bd9Sstevel@tonic-gate uchar_t code[] = { 733*7c478bd9Sstevel@tonic-gate 0x51, 0x50, 0x52, /* pushq %rcx, %rax, %rdx */ 734*7c478bd9Sstevel@tonic-gate 0xb9, 0x00, 0x00, 0x00, 0x00, /* movl $MSRNUM, %ecx */ 735*7c478bd9Sstevel@tonic-gate 0x31, 0xc0, /* clr %eax */ 736*7c478bd9Sstevel@tonic-gate 0x31, 0xd2, /* clr %edx */ 737*7c478bd9Sstevel@tonic-gate 0x0f, 0x30, /* wrmsr */ 738*7c478bd9Sstevel@tonic-gate 0x5a, 0x58, 0x59 /* popq %rdx, %rax, %rcx */ 739*7c478bd9Sstevel@tonic-gate }; 740*7c478bd9Sstevel@tonic-gate uchar_t *patch = &code[4]; 741*7c478bd9Sstevel@tonic-gate #else 742*7c478bd9Sstevel@tonic-gate uchar_t code[] = { 743*7c478bd9Sstevel@tonic-gate 0x60, /* pushal */ 744*7c478bd9Sstevel@tonic-gate 0xb9, 0x00, 0x00, 0x00, 0x00, /* movl $MSRNUM, %ecx */ 745*7c478bd9Sstevel@tonic-gate 0x31, 0xc0, /* clr %eax */ 746*7c478bd9Sstevel@tonic-gate 0x31, 0xd2, /* clr %edx */ 747*7c478bd9Sstevel@tonic-gate 0x0f, 0x30, /* wrmsr */ 748*7c478bd9Sstevel@tonic-gate 0x61 /* popal */ 749*7c478bd9Sstevel@tonic-gate }; 750*7c478bd9Sstevel@tonic-gate uchar_t *patch = &code[2]; 751*7c478bd9Sstevel@tonic-gate #endif 752*7c478bd9Sstevel@tonic-gate 753*7c478bd9Sstevel@tonic-gate bcopy(&msr, patch, sizeof (uint32_t)); 754*7c478bd9Sstevel@tonic-gate 755*7c478bd9Sstevel@tonic-gate kaif_idt_patch((caddr_t)code, sizeof (code)); 756*7c478bd9Sstevel@tonic-gate 757*7c478bd9Sstevel@tonic-gate bcopy(code, &kaif_slave_entry_patch, sizeof (code)); 758*7c478bd9Sstevel@tonic-gate } 759*7c478bd9Sstevel@tonic-gate 760*7c478bd9Sstevel@tonic-gate static void 761*7c478bd9Sstevel@tonic-gate kaif_msr_add_wrexit(uint_t msr, uint64_t *valp) 762*7c478bd9Sstevel@tonic-gate { 763*7c478bd9Sstevel@tonic-gate kaif_msr_wrexit_msr = msr; 764*7c478bd9Sstevel@tonic-gate kaif_msr_wrexit_valp = valp; 765*7c478bd9Sstevel@tonic-gate } 766*7c478bd9Sstevel@tonic-gate 767*7c478bd9Sstevel@tonic-gate static void 768*7c478bd9Sstevel@tonic-gate kaif_msr_add(const kmdb_msr_t *msrs) 769*7c478bd9Sstevel@tonic-gate { 770*7c478bd9Sstevel@tonic-gate kmdb_msr_t *save; 771*7c478bd9Sstevel@tonic-gate int nmsrs, i; 772*7c478bd9Sstevel@tonic-gate 773*7c478bd9Sstevel@tonic-gate ASSERT(kaif_cpusave[0].krs_msr == NULL); 774*7c478bd9Sstevel@tonic-gate 775*7c478bd9Sstevel@tonic-gate for (i = 0; msrs[i].msr_num != 0; i++) { 776*7c478bd9Sstevel@tonic-gate switch (msrs[i].msr_type) { 777*7c478bd9Sstevel@tonic-gate case KMDB_MSR_CLEARENTRY: 778*7c478bd9Sstevel@tonic-gate kaif_msr_add_clrentry(msrs[i].msr_num); 779*7c478bd9Sstevel@tonic-gate break; 780*7c478bd9Sstevel@tonic-gate 781*7c478bd9Sstevel@tonic-gate case KMDB_MSR_WRITEDELAY: 782*7c478bd9Sstevel@tonic-gate kaif_msr_add_wrexit(msrs[i].msr_num, msrs[i].msr_valp); 783*7c478bd9Sstevel@tonic-gate break; 784*7c478bd9Sstevel@tonic-gate } 785*7c478bd9Sstevel@tonic-gate } 786*7c478bd9Sstevel@tonic-gate nmsrs = i + 1; /* we want to copy the terminating kmdb_msr_t too */ 787*7c478bd9Sstevel@tonic-gate 788*7c478bd9Sstevel@tonic-gate save = mdb_zalloc(sizeof (kmdb_msr_t) * nmsrs * kaif_ncpusave, 789*7c478bd9Sstevel@tonic-gate UM_SLEEP); 790*7c478bd9Sstevel@tonic-gate 791*7c478bd9Sstevel@tonic-gate for (i = 0; i < kaif_ncpusave; i++) { 792*7c478bd9Sstevel@tonic-gate bcopy(msrs, &save[nmsrs * i], sizeof (kmdb_msr_t) * nmsrs); 793*7c478bd9Sstevel@tonic-gate kaif_cpusave[i].krs_msr = &save[nmsrs * i]; 794*7c478bd9Sstevel@tonic-gate } 795*7c478bd9Sstevel@tonic-gate } 796*7c478bd9Sstevel@tonic-gate 797*7c478bd9Sstevel@tonic-gate static uint64_t 798*7c478bd9Sstevel@tonic-gate kaif_msr_get(int cpuid, uint_t num) 799*7c478bd9Sstevel@tonic-gate { 800*7c478bd9Sstevel@tonic-gate kmdb_msr_t *msr; 801*7c478bd9Sstevel@tonic-gate int i; 802*7c478bd9Sstevel@tonic-gate 803*7c478bd9Sstevel@tonic-gate if (cpuid == DPI_MASTER_CPUID) 804*7c478bd9Sstevel@tonic-gate cpuid = kaif_master_cpuid; 805*7c478bd9Sstevel@tonic-gate msr = kaif_cpusave[cpuid].krs_msr; 806*7c478bd9Sstevel@tonic-gate 807*7c478bd9Sstevel@tonic-gate for (i = 0; msr[i].msr_num != 0; i++) { 808*7c478bd9Sstevel@tonic-gate if (msr[i].msr_num == num && 809*7c478bd9Sstevel@tonic-gate (msr[i].msr_type & KMDB_MSR_READ)) 810*7c478bd9Sstevel@tonic-gate return (msr[i].msr_val); 811*7c478bd9Sstevel@tonic-gate } 812*7c478bd9Sstevel@tonic-gate 813*7c478bd9Sstevel@tonic-gate return (0); 814*7c478bd9Sstevel@tonic-gate } 815*7c478bd9Sstevel@tonic-gate 816*7c478bd9Sstevel@tonic-gate int 817*7c478bd9Sstevel@tonic-gate kaif_memrange_add(caddr_t base, size_t len) 818*7c478bd9Sstevel@tonic-gate { 819*7c478bd9Sstevel@tonic-gate kaif_memrange_t *mr = &kaif_memranges[kaif_nmemranges]; 820*7c478bd9Sstevel@tonic-gate 821*7c478bd9Sstevel@tonic-gate if (kaif_nmemranges == KAIF_MEMRANGES_MAX) 822*7c478bd9Sstevel@tonic-gate return (set_errno(ENOSPC)); 823*7c478bd9Sstevel@tonic-gate 824*7c478bd9Sstevel@tonic-gate /* 825*7c478bd9Sstevel@tonic-gate * In the unlikely event that someone is stepping through this routine, 826*7c478bd9Sstevel@tonic-gate * we need to make sure that kaif_memranges knows about the new range 827*7c478bd9Sstevel@tonic-gate * before umem gets it. That way the entry code can recognize stacks 828*7c478bd9Sstevel@tonic-gate * allocated from the new region. 829*7c478bd9Sstevel@tonic-gate */ 830*7c478bd9Sstevel@tonic-gate mr->mr_base = base; 831*7c478bd9Sstevel@tonic-gate mr->mr_lim = base + len - 1; 832*7c478bd9Sstevel@tonic-gate kaif_nmemranges++; 833*7c478bd9Sstevel@tonic-gate 834*7c478bd9Sstevel@tonic-gate if (mdb_umem_add(base, len) < 0) { 835*7c478bd9Sstevel@tonic-gate kaif_nmemranges--; 836*7c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 837*7c478bd9Sstevel@tonic-gate } 838*7c478bd9Sstevel@tonic-gate 839*7c478bd9Sstevel@tonic-gate return (0); 840*7c478bd9Sstevel@tonic-gate } 841*7c478bd9Sstevel@tonic-gate 842*7c478bd9Sstevel@tonic-gate void 843*7c478bd9Sstevel@tonic-gate kaif_trap_set_debugger(void) 844*7c478bd9Sstevel@tonic-gate { 845*7c478bd9Sstevel@tonic-gate set_idt(&kaif_idtr); 846*7c478bd9Sstevel@tonic-gate } 847*7c478bd9Sstevel@tonic-gate 848*7c478bd9Sstevel@tonic-gate void 849*7c478bd9Sstevel@tonic-gate kaif_trap_set_saved(kaif_cpusave_t *cpusave) 850*7c478bd9Sstevel@tonic-gate { 851*7c478bd9Sstevel@tonic-gate set_idt(&cpusave->krs_idtr); 852*7c478bd9Sstevel@tonic-gate } 853*7c478bd9Sstevel@tonic-gate 854*7c478bd9Sstevel@tonic-gate static int 855*7c478bd9Sstevel@tonic-gate kaif_init(kmdb_auxv_t *kav) 856*7c478bd9Sstevel@tonic-gate { 857*7c478bd9Sstevel@tonic-gate int i; 858*7c478bd9Sstevel@tonic-gate 859*7c478bd9Sstevel@tonic-gate /* Allocate the per-CPU save areas */ 860*7c478bd9Sstevel@tonic-gate kaif_cpusave = mdb_zalloc(sizeof (kaif_cpusave_t) * kav->kav_ncpu, 861*7c478bd9Sstevel@tonic-gate UM_SLEEP); 862*7c478bd9Sstevel@tonic-gate kaif_ncpusave = kav->kav_ncpu; 863*7c478bd9Sstevel@tonic-gate 864*7c478bd9Sstevel@tonic-gate for (i = 0; i < kaif_ncpusave; i++) { 865*7c478bd9Sstevel@tonic-gate kaif_cpusave[i].krs_cpu_id = i; 866*7c478bd9Sstevel@tonic-gate 867*7c478bd9Sstevel@tonic-gate kaif_cpusave[i].krs_curcrumb = 868*7c478bd9Sstevel@tonic-gate &kaif_cpusave[i].krs_crumbs[KAIF_NCRUMBS - 1]; 869*7c478bd9Sstevel@tonic-gate kaif_cpusave[i].krs_curcrumbidx = KAIF_NCRUMBS - 1; 870*7c478bd9Sstevel@tonic-gate } 871*7c478bd9Sstevel@tonic-gate 872*7c478bd9Sstevel@tonic-gate kaif_idt_init(); 873*7c478bd9Sstevel@tonic-gate 874*7c478bd9Sstevel@tonic-gate /* The initial selector set. Updated by the debugger-entry code */ 875*7c478bd9Sstevel@tonic-gate #ifndef __amd64 876*7c478bd9Sstevel@tonic-gate kaif_cs = BOOTCODE_SEL; 877*7c478bd9Sstevel@tonic-gate kaif_ds = kaif_fs = kaif_gs = BOOTFLAT_SEL; 878*7c478bd9Sstevel@tonic-gate #endif 879*7c478bd9Sstevel@tonic-gate 880*7c478bd9Sstevel@tonic-gate kaif_memranges[0].mr_base = kav->kav_dseg; 881*7c478bd9Sstevel@tonic-gate kaif_memranges[0].mr_lim = kav->kav_dseg + kav->kav_dseg_size - 1; 882*7c478bd9Sstevel@tonic-gate kaif_nmemranges = 1; 883*7c478bd9Sstevel@tonic-gate 884*7c478bd9Sstevel@tonic-gate kaif_modchg_cb = NULL; 885*7c478bd9Sstevel@tonic-gate 886*7c478bd9Sstevel@tonic-gate kaif_waptmap = 0; 887*7c478bd9Sstevel@tonic-gate 888*7c478bd9Sstevel@tonic-gate kaif_drreg.dr_ctl = KREG_DRCTL_RESERVED; 889*7c478bd9Sstevel@tonic-gate kaif_drreg.dr_stat = KREG_DRSTAT_RESERVED; 890*7c478bd9Sstevel@tonic-gate 891*7c478bd9Sstevel@tonic-gate kaif_msr_wrexit_msr = 0; 892*7c478bd9Sstevel@tonic-gate kaif_msr_wrexit_valp = NULL; 893*7c478bd9Sstevel@tonic-gate 894*7c478bd9Sstevel@tonic-gate kaif_trap_switch = (kav->kav_flags & KMDB_AUXV_FL_NOTRPSWTCH) == 0; 895*7c478bd9Sstevel@tonic-gate 896*7c478bd9Sstevel@tonic-gate if ((kaif_sys_sysenter = kmdb_kdi_lookup_by_name("unix", 897*7c478bd9Sstevel@tonic-gate "sys_sysenter")) == NULL) 898*7c478bd9Sstevel@tonic-gate return (set_errno(ENOENT)); 899*7c478bd9Sstevel@tonic-gate 900*7c478bd9Sstevel@tonic-gate return (0); 901*7c478bd9Sstevel@tonic-gate } 902*7c478bd9Sstevel@tonic-gate 903*7c478bd9Sstevel@tonic-gate dpi_ops_t kmdb_dpi_ops = { 904*7c478bd9Sstevel@tonic-gate kaif_init, 905*7c478bd9Sstevel@tonic-gate kaif_activate, 906*7c478bd9Sstevel@tonic-gate kaif_deactivate, 907*7c478bd9Sstevel@tonic-gate kaif_enter_mon, 908*7c478bd9Sstevel@tonic-gate kaif_modchg_register, 909*7c478bd9Sstevel@tonic-gate kaif_modchg_cancel, 910*7c478bd9Sstevel@tonic-gate kaif_get_cpu_state, 911*7c478bd9Sstevel@tonic-gate kaif_get_master_cpuid, 912*7c478bd9Sstevel@tonic-gate kaif_get_gregs, 913*7c478bd9Sstevel@tonic-gate kaif_get_cpu_register, 914*7c478bd9Sstevel@tonic-gate kaif_set_cpu_register, 915*7c478bd9Sstevel@tonic-gate kaif_brkpt_arm, 916*7c478bd9Sstevel@tonic-gate kaif_brkpt_disarm, 917*7c478bd9Sstevel@tonic-gate kaif_wapt_validate, 918*7c478bd9Sstevel@tonic-gate kaif_wapt_reserve, 919*7c478bd9Sstevel@tonic-gate kaif_wapt_release, 920*7c478bd9Sstevel@tonic-gate kaif_wapt_arm, 921*7c478bd9Sstevel@tonic-gate kaif_wapt_disarm, 922*7c478bd9Sstevel@tonic-gate kaif_wapt_match, 923*7c478bd9Sstevel@tonic-gate kaif_step, 924*7c478bd9Sstevel@tonic-gate kaif_step_branch, 925*7c478bd9Sstevel@tonic-gate kaif_call, 926*7c478bd9Sstevel@tonic-gate kaif_dump_crumbs, 927*7c478bd9Sstevel@tonic-gate kaif_memrange_add, 928*7c478bd9Sstevel@tonic-gate kaif_msr_add, 929*7c478bd9Sstevel@tonic-gate kaif_msr_get, 930*7c478bd9Sstevel@tonic-gate }; 931