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