10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 23*1234Sjohnlev * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * The debugger/"PROM" interface layer 310Sstevel@tonic-gate * 320Sstevel@tonic-gate * (it makes more sense on SPARC) 330Sstevel@tonic-gate */ 340Sstevel@tonic-gate 350Sstevel@tonic-gate #include <kmdb/kmdb_dpi_impl.h> 360Sstevel@tonic-gate #include <kmdb/kmdb_kdi.h> 370Sstevel@tonic-gate #include <kmdb/kmdb_umemglue.h> 380Sstevel@tonic-gate #include <kmdb/kaif.h> 390Sstevel@tonic-gate #include <kmdb/kaif_asmutil.h> 400Sstevel@tonic-gate #include <mdb/mdb_err.h> 410Sstevel@tonic-gate #include <mdb/mdb_debug.h> 420Sstevel@tonic-gate #include <mdb/mdb_isautil.h> 430Sstevel@tonic-gate #include <mdb/mdb_io_impl.h> 440Sstevel@tonic-gate #include <mdb/mdb_kreg.h> 450Sstevel@tonic-gate #include <mdb/mdb.h> 460Sstevel@tonic-gate 470Sstevel@tonic-gate #include <sys/types.h> 480Sstevel@tonic-gate #include <sys/segments.h> 490Sstevel@tonic-gate #include <sys/bitmap.h> 500Sstevel@tonic-gate 510Sstevel@tonic-gate kaif_cpusave_t *kaif_cpusave; 520Sstevel@tonic-gate int kaif_ncpusave; 530Sstevel@tonic-gate 540Sstevel@tonic-gate kaif_drreg_t kaif_drreg; 550Sstevel@tonic-gate 560Sstevel@tonic-gate uint32_t kaif_waptmap; 570Sstevel@tonic-gate 580Sstevel@tonic-gate #ifndef __amd64 590Sstevel@tonic-gate /* Used to track the current set of valid kernel selectors. */ 600Sstevel@tonic-gate uint32_t kaif_cs; 610Sstevel@tonic-gate uint32_t kaif_ds; 620Sstevel@tonic-gate uint32_t kaif_fs; 630Sstevel@tonic-gate uint32_t kaif_gs; 640Sstevel@tonic-gate #endif 650Sstevel@tonic-gate 660Sstevel@tonic-gate uint_t kaif_msr_wrexit_msr; 670Sstevel@tonic-gate uint64_t *kaif_msr_wrexit_valp; 680Sstevel@tonic-gate 690Sstevel@tonic-gate uintptr_t kaif_kernel_handler; 700Sstevel@tonic-gate uintptr_t kaif_sys_sysenter; 710Sstevel@tonic-gate 720Sstevel@tonic-gate int kaif_trap_switch; 730Sstevel@tonic-gate 740Sstevel@tonic-gate void (*kaif_modchg_cb)(struct modctl *, int); 750Sstevel@tonic-gate 760Sstevel@tonic-gate #define KAIF_MEMRANGES_MAX 2 770Sstevel@tonic-gate 780Sstevel@tonic-gate kaif_memrange_t kaif_memranges[KAIF_MEMRANGES_MAX]; 790Sstevel@tonic-gate int kaif_nmemranges; 800Sstevel@tonic-gate 810Sstevel@tonic-gate enum { 820Sstevel@tonic-gate M_SYSRET = 0x07, /* after M_ESC */ 830Sstevel@tonic-gate M_ESC = 0x0f, 840Sstevel@tonic-gate M_SYSEXIT = 0x35, /* after M_ESC */ 850Sstevel@tonic-gate M_REX_LO = 0x40, /* first REX prefix */ 860Sstevel@tonic-gate M_REX_HI = 0x4f, /* last REX prefix */ 870Sstevel@tonic-gate M_PUSHF = 0x9c, /* pushfl and pushfq */ 880Sstevel@tonic-gate M_POPF = 0x9d, /* popfl and popfq */ 890Sstevel@tonic-gate M_INT3 = 0xcc, 900Sstevel@tonic-gate M_INTX = 0xcd, 910Sstevel@tonic-gate M_INTO = 0xce, 920Sstevel@tonic-gate M_IRET = 0xcf, 930Sstevel@tonic-gate M_CLI = 0xfa, 940Sstevel@tonic-gate M_STI = 0xfb 950Sstevel@tonic-gate }; 960Sstevel@tonic-gate 970Sstevel@tonic-gate #define KAIF_BREAKPOINT_INSTR M_INT3 980Sstevel@tonic-gate 990Sstevel@tonic-gate #define KAIF_WPPRIV2ID(wp) (int)(uintptr_t)((wp)->wp_priv) 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate #ifdef __amd64 1020Sstevel@tonic-gate #define FLAGS_REG_NAME "rflags" 1030Sstevel@tonic-gate #else 1040Sstevel@tonic-gate #define FLAGS_REG_NAME "eflags" 1050Sstevel@tonic-gate #endif 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate /* 1080Sstevel@tonic-gate * Called during normal debugger operation and during debugger faults. 1090Sstevel@tonic-gate */ 1100Sstevel@tonic-gate static void 1110Sstevel@tonic-gate kaif_enter_mon(void) 1120Sstevel@tonic-gate { 1130Sstevel@tonic-gate char c; 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate for (;;) { 1160Sstevel@tonic-gate mdb_iob_printf(mdb.m_out, 1170Sstevel@tonic-gate "%s: Do you really want to reboot? (y/n) ", 1180Sstevel@tonic-gate mdb.m_pname); 1190Sstevel@tonic-gate mdb_iob_flush(mdb.m_out); 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate while (IOP_READ(mdb.m_term, &c, 1) != 1) 1220Sstevel@tonic-gate continue; 1230Sstevel@tonic-gate mdb_iob_printf(mdb.m_out, "%c%s", c, (c == '\n' ? "" : "\n")); 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate if (c == 'n' || c == 'N') 1260Sstevel@tonic-gate return; 1270Sstevel@tonic-gate else if (c == 'y' || c == 'Y') { 1280Sstevel@tonic-gate mdb_iob_printf(mdb.m_out, "Rebooting...\n"); 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate kmdb_dpi_reboot(); 1310Sstevel@tonic-gate } 1320Sstevel@tonic-gate } 1330Sstevel@tonic-gate } 1340Sstevel@tonic-gate 135*1234Sjohnlev static kaif_cpusave_t * 136*1234Sjohnlev kaif_cpuid2save(int cpuid) 137*1234Sjohnlev { 138*1234Sjohnlev kaif_cpusave_t *save; 139*1234Sjohnlev 140*1234Sjohnlev if (cpuid == DPI_MASTER_CPUID) 141*1234Sjohnlev return (&kaif_cpusave[kaif_master_cpuid]); 142*1234Sjohnlev 143*1234Sjohnlev if (cpuid < 0 || cpuid >= kaif_ncpusave) { 144*1234Sjohnlev (void) set_errno(EINVAL); 145*1234Sjohnlev return (NULL); 146*1234Sjohnlev } 147*1234Sjohnlev 148*1234Sjohnlev save = &kaif_cpusave[cpuid]; 149*1234Sjohnlev 150*1234Sjohnlev if (save->krs_cpu_state != KAIF_CPU_STATE_MASTER && 151*1234Sjohnlev save->krs_cpu_state != KAIF_CPU_STATE_SLAVE) { 152*1234Sjohnlev (void) set_errno(EINVAL); 153*1234Sjohnlev return (NULL); 154*1234Sjohnlev } 155*1234Sjohnlev 156*1234Sjohnlev return (save); 157*1234Sjohnlev } 158*1234Sjohnlev 1590Sstevel@tonic-gate static int 1600Sstevel@tonic-gate kaif_get_cpu_state(int cpuid) 1610Sstevel@tonic-gate { 162*1234Sjohnlev kaif_cpusave_t *save; 1630Sstevel@tonic-gate 164*1234Sjohnlev if ((save = kaif_cpuid2save(cpuid)) == NULL) 165*1234Sjohnlev return (-1); /* errno is set for us */ 1660Sstevel@tonic-gate 167*1234Sjohnlev switch (save->krs_cpu_state) { 1680Sstevel@tonic-gate case KAIF_CPU_STATE_MASTER: 1690Sstevel@tonic-gate return (DPI_CPU_STATE_MASTER); 1700Sstevel@tonic-gate case KAIF_CPU_STATE_SLAVE: 1710Sstevel@tonic-gate return (DPI_CPU_STATE_SLAVE); 1720Sstevel@tonic-gate default: 1730Sstevel@tonic-gate return (set_errno(EINVAL)); 1740Sstevel@tonic-gate } 1750Sstevel@tonic-gate } 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate static int 1780Sstevel@tonic-gate kaif_get_master_cpuid(void) 1790Sstevel@tonic-gate { 1800Sstevel@tonic-gate return (kaif_master_cpuid); 1810Sstevel@tonic-gate } 1820Sstevel@tonic-gate 1830Sstevel@tonic-gate static const mdb_tgt_gregset_t * 1840Sstevel@tonic-gate kaif_get_gregs(int cpuid) 1850Sstevel@tonic-gate { 186*1234Sjohnlev kaif_cpusave_t *save; 1870Sstevel@tonic-gate 188*1234Sjohnlev if ((save = kaif_cpuid2save(cpuid)) == NULL) 189*1234Sjohnlev return (NULL); /* errno is set for us */ 1900Sstevel@tonic-gate 191*1234Sjohnlev return (save->krs_gregs); 1920Sstevel@tonic-gate } 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate typedef struct kaif_reg_synonyms { 1950Sstevel@tonic-gate const char *rs_syn; 1960Sstevel@tonic-gate const char *rs_name; 1970Sstevel@tonic-gate } kaif_reg_synonyms_t; 1980Sstevel@tonic-gate 1990Sstevel@tonic-gate static kreg_t * 200*1234Sjohnlev kaif_find_regp(const char *regname) 2010Sstevel@tonic-gate { 2020Sstevel@tonic-gate static const kaif_reg_synonyms_t synonyms[] = { 2030Sstevel@tonic-gate #ifdef __amd64 2040Sstevel@tonic-gate { "pc", "rip" }, 2050Sstevel@tonic-gate { "sp", "rsp" }, 2060Sstevel@tonic-gate { "fp", "rbp" }, 2070Sstevel@tonic-gate #else 2080Sstevel@tonic-gate { "pc", "eip" }, 2090Sstevel@tonic-gate { "sp", "esp" }, 2100Sstevel@tonic-gate { "fp", "ebp" }, 2110Sstevel@tonic-gate #endif 2120Sstevel@tonic-gate { "tt", "trapno" } 2130Sstevel@tonic-gate }; 214*1234Sjohnlev 215*1234Sjohnlev kaif_cpusave_t *save; 2160Sstevel@tonic-gate int i; 2170Sstevel@tonic-gate 218*1234Sjohnlev save = kaif_cpuid2save(DPI_MASTER_CPUID); 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate for (i = 0; i < sizeof (synonyms) / sizeof (synonyms[0]); i++) { 2210Sstevel@tonic-gate if (strcmp(synonyms[i].rs_syn, regname) == 0) 2220Sstevel@tonic-gate regname = synonyms[i].rs_name; 2230Sstevel@tonic-gate } 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate for (i = 0; mdb_isa_kregs[i].rd_name != NULL; i++) { 2260Sstevel@tonic-gate const mdb_tgt_regdesc_t *rd = &mdb_isa_kregs[i]; 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate if (strcmp(rd->rd_name, regname) == 0) 229*1234Sjohnlev return (&save->krs_gregs->kregs[rd->rd_num]); 2300Sstevel@tonic-gate } 2310Sstevel@tonic-gate 2320Sstevel@tonic-gate (void) set_errno(ENOENT); 2330Sstevel@tonic-gate return (NULL); 2340Sstevel@tonic-gate } 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate /*ARGSUSED*/ 2370Sstevel@tonic-gate static int 238*1234Sjohnlev kaif_get_register(const char *regname, kreg_t *valp) 2390Sstevel@tonic-gate { 2400Sstevel@tonic-gate kreg_t *regp; 2410Sstevel@tonic-gate 242*1234Sjohnlev if ((regp = kaif_find_regp(regname)) == NULL) 2430Sstevel@tonic-gate return (-1); 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate *valp = *regp; 2460Sstevel@tonic-gate 2470Sstevel@tonic-gate return (0); 2480Sstevel@tonic-gate } 2490Sstevel@tonic-gate 2500Sstevel@tonic-gate static int 251*1234Sjohnlev kaif_set_register(const char *regname, kreg_t val) 2520Sstevel@tonic-gate { 2530Sstevel@tonic-gate kreg_t *regp; 2540Sstevel@tonic-gate 255*1234Sjohnlev if ((regp = kaif_find_regp(regname)) == NULL) 2560Sstevel@tonic-gate return (-1); 2570Sstevel@tonic-gate 2580Sstevel@tonic-gate *regp = val; 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate return (0); 2610Sstevel@tonic-gate } 2620Sstevel@tonic-gate 2630Sstevel@tonic-gate static int 2640Sstevel@tonic-gate kaif_brkpt_arm(uintptr_t addr, mdb_instr_t *instrp) 2650Sstevel@tonic-gate { 2660Sstevel@tonic-gate mdb_instr_t bkpt = KAIF_BREAKPOINT_INSTR; 2670Sstevel@tonic-gate 2680Sstevel@tonic-gate if (mdb_tgt_vread(mdb.m_target, instrp, sizeof (mdb_instr_t), addr) != 2690Sstevel@tonic-gate sizeof (mdb_instr_t)) 2700Sstevel@tonic-gate return (-1); /* errno is set for us */ 2710Sstevel@tonic-gate 2720Sstevel@tonic-gate if (mdb_tgt_vwrite(mdb.m_target, &bkpt, sizeof (mdb_instr_t), addr) != 2730Sstevel@tonic-gate sizeof (mdb_instr_t)) 2740Sstevel@tonic-gate return (-1); /* errno is set for us */ 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate return (0); 2770Sstevel@tonic-gate } 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate static int 2800Sstevel@tonic-gate kaif_brkpt_disarm(uintptr_t addr, mdb_instr_t instrp) 2810Sstevel@tonic-gate { 2820Sstevel@tonic-gate if (mdb_tgt_vwrite(mdb.m_target, &instrp, sizeof (mdb_instr_t), addr) != 2830Sstevel@tonic-gate sizeof (mdb_instr_t)) 2840Sstevel@tonic-gate return (-1); /* errno is set for us */ 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate return (0); 2870Sstevel@tonic-gate } 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate /* 2900Sstevel@tonic-gate * Intel watchpoints are even more fun than SPARC ones. The Intel architecture 2910Sstevel@tonic-gate * manuals refer to watchpoints as breakpoints. For consistency with the 2920Sstevel@tonic-gate * terminology used in other portions of kmdb, we will, however, refer to them 2930Sstevel@tonic-gate * as watchpoints. 2940Sstevel@tonic-gate * 2950Sstevel@tonic-gate * Execute, data write, I/O read/write, and data read/write watchpoints are 2960Sstevel@tonic-gate * supported by the hardware. Execute watchpoints must be one byte in length, 2970Sstevel@tonic-gate * and must be placed on the first byte of the instruction to be watched. 2980Sstevel@tonic-gate * Lengths of other watchpoints are more varied. 2990Sstevel@tonic-gate * 3000Sstevel@tonic-gate * Given that we already have a breakpoint facility, and given the restrictions 3010Sstevel@tonic-gate * placed on execute watchpoints, we're going to disallow the creation of 3020Sstevel@tonic-gate * execute watchpoints. The others will be fully supported. See the Debugging 3030Sstevel@tonic-gate * chapter in both the IA32 and AMD64 System Programming books for more details. 3040Sstevel@tonic-gate */ 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate #ifdef __amd64 3070Sstevel@tonic-gate #define WAPT_DATA_MAX_SIZE 8 3080Sstevel@tonic-gate #define WAPT_DATA_SIZES_MSG "1, 2, 4, or 8" 3090Sstevel@tonic-gate #else 3100Sstevel@tonic-gate #define WAPT_DATA_MAX_SIZE 4 3110Sstevel@tonic-gate #define WAPT_DATA_SIZES_MSG "1, 2, or 4" 3120Sstevel@tonic-gate #endif 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate static int 3150Sstevel@tonic-gate kaif_wapt_validate(kmdb_wapt_t *wp) 3160Sstevel@tonic-gate { 3170Sstevel@tonic-gate if (wp->wp_type == DPI_WAPT_TYPE_IO) { 3180Sstevel@tonic-gate if (wp->wp_wflags != (MDB_TGT_WA_R | MDB_TGT_WA_W)) { 3190Sstevel@tonic-gate warn("I/O port watchpoints must be read/write\n"); 3200Sstevel@tonic-gate return (set_errno(EINVAL)); 3210Sstevel@tonic-gate } 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate if (wp->wp_size != 1 && wp->wp_size != 2 && wp->wp_size != 4) { 3240Sstevel@tonic-gate warn("I/O watchpoint size must be 1, 2, or 4 bytes\n"); 3250Sstevel@tonic-gate return (set_errno(EINVAL)); 3260Sstevel@tonic-gate } 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate } else if (wp->wp_type == DPI_WAPT_TYPE_PHYS) { 3290Sstevel@tonic-gate warn("physical address watchpoints are not supported on this " 3300Sstevel@tonic-gate "platform\n"); 3310Sstevel@tonic-gate return (set_errno(EMDB_TGTHWNOTSUP)); 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate } else { 3340Sstevel@tonic-gate if (wp->wp_wflags != (MDB_TGT_WA_R | MDB_TGT_WA_W) && 3350Sstevel@tonic-gate wp->wp_wflags != MDB_TGT_WA_W) { 3360Sstevel@tonic-gate warn("watchpoints must be read/write or write-only\n"); 3370Sstevel@tonic-gate return (set_errno(EINVAL)); 3380Sstevel@tonic-gate } 3390Sstevel@tonic-gate 3400Sstevel@tonic-gate if ((wp->wp_size & -(wp->wp_size)) != wp->wp_size || 3410Sstevel@tonic-gate wp->wp_size > WAPT_DATA_MAX_SIZE) { 3420Sstevel@tonic-gate warn("data watchpoint size must be " WAPT_DATA_SIZES_MSG 3430Sstevel@tonic-gate " bytes\n"); 3440Sstevel@tonic-gate return (set_errno(EINVAL)); 3450Sstevel@tonic-gate } 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate } 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate if (wp->wp_addr & (wp->wp_size - 1)) { 3500Sstevel@tonic-gate warn("%lu-byte watchpoints must be %lu-byte aligned\n", 3510Sstevel@tonic-gate (ulong_t)wp->wp_size, (ulong_t)wp->wp_size); 3520Sstevel@tonic-gate return (set_errno(EINVAL)); 3530Sstevel@tonic-gate } 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate return (0); 3560Sstevel@tonic-gate } 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate static int 3590Sstevel@tonic-gate kaif_wapt_reserve(kmdb_wapt_t *wp) 3600Sstevel@tonic-gate { 3610Sstevel@tonic-gate int id; 3620Sstevel@tonic-gate 3630Sstevel@tonic-gate for (id = 0; id <= KREG_MAXWPIDX; id++) { 3640Sstevel@tonic-gate if (!BT_TEST(&kaif_waptmap, id)) { 3650Sstevel@tonic-gate /* found one */ 3660Sstevel@tonic-gate BT_SET(&kaif_waptmap, id); 3670Sstevel@tonic-gate wp->wp_priv = (void *)(uintptr_t)id; 3680Sstevel@tonic-gate return (0); 3690Sstevel@tonic-gate } 3700Sstevel@tonic-gate } 3710Sstevel@tonic-gate 3720Sstevel@tonic-gate return (set_errno(EMDB_WPTOOMANY)); 3730Sstevel@tonic-gate } 3740Sstevel@tonic-gate 3750Sstevel@tonic-gate static void 3760Sstevel@tonic-gate kaif_wapt_release(kmdb_wapt_t *wp) 3770Sstevel@tonic-gate { 3780Sstevel@tonic-gate int id = KAIF_WPPRIV2ID(wp); 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate ASSERT(BT_TEST(&kaif_waptmap, id)); 3810Sstevel@tonic-gate BT_CLEAR(&kaif_waptmap, id); 3820Sstevel@tonic-gate } 3830Sstevel@tonic-gate 3840Sstevel@tonic-gate /*ARGSUSED*/ 3850Sstevel@tonic-gate static void 3860Sstevel@tonic-gate kaif_wapt_arm(kmdb_wapt_t *wp) 3870Sstevel@tonic-gate { 3880Sstevel@tonic-gate uint_t rw; 3890Sstevel@tonic-gate int hwid = KAIF_WPPRIV2ID(wp); 3900Sstevel@tonic-gate 3910Sstevel@tonic-gate ASSERT(BT_TEST(&kaif_waptmap, hwid)); 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate if (wp->wp_type == DPI_WAPT_TYPE_IO) 3940Sstevel@tonic-gate rw = KREG_DRCTL_WP_IORW; 3950Sstevel@tonic-gate else if (wp->wp_wflags & MDB_TGT_WA_R) 3960Sstevel@tonic-gate rw = KREG_DRCTL_WP_RW; 3970Sstevel@tonic-gate else if (wp->wp_wflags & MDB_TGT_WA_X) 3980Sstevel@tonic-gate rw = KREG_DRCTL_WP_EXEC; 3990Sstevel@tonic-gate else 4000Sstevel@tonic-gate rw = KREG_DRCTL_WP_WONLY; 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate kaif_drreg.dr_addr[hwid] = wp->wp_addr; 4030Sstevel@tonic-gate 4040Sstevel@tonic-gate kaif_drreg.dr_ctl &= ~KREG_DRCTL_WP_MASK(hwid); 4050Sstevel@tonic-gate kaif_drreg.dr_ctl |= KREG_DRCTL_WP_LENRW(hwid, wp->wp_size - 1, rw); 4060Sstevel@tonic-gate kaif_drreg.dr_ctl |= KREG_DRCTL_WPEN(hwid); 4070Sstevel@tonic-gate } 4080Sstevel@tonic-gate 4090Sstevel@tonic-gate /*ARGSUSED*/ 4100Sstevel@tonic-gate static void 4110Sstevel@tonic-gate kaif_wapt_disarm(kmdb_wapt_t *wp) 4120Sstevel@tonic-gate { 4130Sstevel@tonic-gate int hwid = KAIF_WPPRIV2ID(wp); 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate ASSERT(BT_TEST(&kaif_waptmap, hwid)); 4160Sstevel@tonic-gate 4170Sstevel@tonic-gate kaif_drreg.dr_addr[hwid] = 0; 4180Sstevel@tonic-gate kaif_drreg.dr_ctl &= ~(KREG_DRCTL_WP_MASK(hwid) | 4190Sstevel@tonic-gate KREG_DRCTL_WPEN_MASK(hwid)); 4200Sstevel@tonic-gate } 4210Sstevel@tonic-gate 4220Sstevel@tonic-gate /*ARGSUSED*/ 4230Sstevel@tonic-gate static int 4240Sstevel@tonic-gate kaif_wapt_match(kmdb_wapt_t *wp) 4250Sstevel@tonic-gate { 4260Sstevel@tonic-gate int hwid = KAIF_WPPRIV2ID(wp); 4270Sstevel@tonic-gate uint32_t mask = KREG_DRSTAT_WP_MASK(hwid); 4280Sstevel@tonic-gate int n = 0; 4290Sstevel@tonic-gate int i; 4300Sstevel@tonic-gate 4310Sstevel@tonic-gate ASSERT(BT_TEST(&kaif_waptmap, hwid)); 4320Sstevel@tonic-gate 4330Sstevel@tonic-gate for (i = 0; i < kaif_ncpusave; i++) 4340Sstevel@tonic-gate n += (kaif_cpusave[i].krs_dr.dr_stat & mask) != 0; 4350Sstevel@tonic-gate 4360Sstevel@tonic-gate return (n); 4370Sstevel@tonic-gate } 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate static int 4400Sstevel@tonic-gate kaif_step(void) 4410Sstevel@tonic-gate { 4420Sstevel@tonic-gate kreg_t pc, fl, oldfl, newfl, sp; 4430Sstevel@tonic-gate mdb_tgt_addr_t npc; 4440Sstevel@tonic-gate mdb_instr_t instr; 4450Sstevel@tonic-gate int emulated = 0, rchk = 0; 4460Sstevel@tonic-gate size_t pcoff = 0; 4470Sstevel@tonic-gate 4480Sstevel@tonic-gate (void) kmdb_dpi_get_register("pc", &pc); 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate if ((npc = mdb_dis_nextins(mdb.m_disasm, mdb.m_target, 4510Sstevel@tonic-gate MDB_TGT_AS_VIRT, pc)) == pc) { 4520Sstevel@tonic-gate warn("failed to decode instruction at %a for step\n", pc); 4530Sstevel@tonic-gate return (set_errno(EINVAL)); 4540Sstevel@tonic-gate } 4550Sstevel@tonic-gate 4560Sstevel@tonic-gate /* 4570Sstevel@tonic-gate * Stepping behavior depends on the type of instruction. It does not 4580Sstevel@tonic-gate * depend on the presence of a REX prefix, as the action we take for a 4590Sstevel@tonic-gate * given instruction doesn't currently vary for 32-bit instructions 4600Sstevel@tonic-gate * versus their 64-bit counterparts. 4610Sstevel@tonic-gate */ 4620Sstevel@tonic-gate do { 4630Sstevel@tonic-gate if (mdb_tgt_vread(mdb.m_target, &instr, sizeof (mdb_instr_t), 4640Sstevel@tonic-gate pc + pcoff) != sizeof (mdb_instr_t)) { 4650Sstevel@tonic-gate warn("failed to read at %p for step", 4660Sstevel@tonic-gate (void *)(pc + pcoff)); 4670Sstevel@tonic-gate return (-1); 4680Sstevel@tonic-gate } 4690Sstevel@tonic-gate } while (pcoff++, (instr >= M_REX_LO && instr <= M_REX_HI && !rchk++)); 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate switch (instr) { 4720Sstevel@tonic-gate case M_IRET: 4730Sstevel@tonic-gate warn("iret cannot be stepped\n"); 4740Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP)); 4750Sstevel@tonic-gate 4760Sstevel@tonic-gate case M_INT3: 4770Sstevel@tonic-gate case M_INTX: 4780Sstevel@tonic-gate case M_INTO: 4790Sstevel@tonic-gate warn("int cannot be stepped\n"); 4800Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP)); 4810Sstevel@tonic-gate 4820Sstevel@tonic-gate case M_ESC: 4830Sstevel@tonic-gate if (mdb_tgt_vread(mdb.m_target, &instr, sizeof (mdb_instr_t), 4840Sstevel@tonic-gate pc + pcoff) != sizeof (mdb_instr_t)) { 4850Sstevel@tonic-gate warn("failed to read at %p for step", 4860Sstevel@tonic-gate (void *)(pc + pcoff)); 4870Sstevel@tonic-gate return (-1); 4880Sstevel@tonic-gate } 4890Sstevel@tonic-gate 4900Sstevel@tonic-gate switch (instr) { 4910Sstevel@tonic-gate case M_SYSRET: 4920Sstevel@tonic-gate warn("sysret cannot be stepped\n"); 4930Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP)); 4940Sstevel@tonic-gate case M_SYSEXIT: 4950Sstevel@tonic-gate warn("sysexit cannot be stepped\n"); 4960Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP)); 4970Sstevel@tonic-gate } 4980Sstevel@tonic-gate break; 4990Sstevel@tonic-gate 5000Sstevel@tonic-gate /* 5010Sstevel@tonic-gate * Some instructions need to be emulated. We need to prevent direct 5020Sstevel@tonic-gate * manipulations of EFLAGS, so we'll emulate cli, sti. pushfl and 5030Sstevel@tonic-gate * popfl also receive special handling, as they manipulate both EFLAGS 5040Sstevel@tonic-gate * and %esp. 5050Sstevel@tonic-gate */ 5060Sstevel@tonic-gate case M_CLI: 5070Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl); 5080Sstevel@tonic-gate fl &= ~KREG_EFLAGS_IF_MASK; 5090Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, fl); 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate emulated = 1; 5120Sstevel@tonic-gate break; 5130Sstevel@tonic-gate 5140Sstevel@tonic-gate case M_STI: 5150Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl); 5160Sstevel@tonic-gate fl |= (1 << KREG_EFLAGS_IF_SHIFT); 5170Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, fl); 5180Sstevel@tonic-gate 5190Sstevel@tonic-gate emulated = 1; 5200Sstevel@tonic-gate break; 5210Sstevel@tonic-gate 5220Sstevel@tonic-gate case M_POPF: 5230Sstevel@tonic-gate /* 5240Sstevel@tonic-gate * popfl will restore a pushed EFLAGS from the stack, and could 5250Sstevel@tonic-gate * in so doing cause IF to be turned on, if only for a a brief 5260Sstevel@tonic-gate * period. To avoid this, we'll secretly replace the stack's 5270Sstevel@tonic-gate * EFLAGS with our decaffeinated brand. We'll then manually 5280Sstevel@tonic-gate * load our EFLAGS copy with the real verion after the step. 5290Sstevel@tonic-gate */ 5300Sstevel@tonic-gate (void) kmdb_dpi_get_register("sp", &sp); 5310Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl); 5320Sstevel@tonic-gate 5330Sstevel@tonic-gate if (mdb_tgt_vread(mdb.m_target, &newfl, sizeof (kreg_t), 5340Sstevel@tonic-gate sp) != sizeof (kreg_t)) { 5350Sstevel@tonic-gate warn("failed to read " FLAGS_REG_NAME 5360Sstevel@tonic-gate " at %p for popfl step\n", (void *)sp); 5370Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */ 5380Sstevel@tonic-gate } 5390Sstevel@tonic-gate 5400Sstevel@tonic-gate fl = (fl & ~KREG_EFLAGS_IF_MASK) | KREG_EFLAGS_TF_MASK; 5410Sstevel@tonic-gate 5420Sstevel@tonic-gate if (mdb_tgt_vwrite(mdb.m_target, &fl, sizeof (kreg_t), 5430Sstevel@tonic-gate sp) != sizeof (kreg_t)) { 5440Sstevel@tonic-gate warn("failed to update " FLAGS_REG_NAME 5450Sstevel@tonic-gate " at %p for popfl step\n", (void *)sp); 5460Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */ 5470Sstevel@tonic-gate } 5480Sstevel@tonic-gate break; 5490Sstevel@tonic-gate } 5500Sstevel@tonic-gate 5510Sstevel@tonic-gate if (emulated) { 5520Sstevel@tonic-gate (void) kmdb_dpi_set_register("pc", npc); 5530Sstevel@tonic-gate return (0); 5540Sstevel@tonic-gate } 5550Sstevel@tonic-gate 5560Sstevel@tonic-gate /* Do the step with IF off, and TF (step) on */ 5570Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &oldfl); 5580Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, 5590Sstevel@tonic-gate ((oldfl | (1 << KREG_EFLAGS_TF_SHIFT)) & ~KREG_EFLAGS_IF_MASK)); 5600Sstevel@tonic-gate 5610Sstevel@tonic-gate kmdb_dpi_resume_master(); /* ... there and back again ... */ 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate /* EFLAGS has now changed, and may require tuning */ 5640Sstevel@tonic-gate 5650Sstevel@tonic-gate switch (instr) { 5660Sstevel@tonic-gate case M_POPF: 5670Sstevel@tonic-gate /* 5680Sstevel@tonic-gate * Use the EFLAGS we grabbed before the pop - see the pre-step 5690Sstevel@tonic-gate * M_POPFL comment. 5700Sstevel@tonic-gate */ 5710Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, newfl); 5720Sstevel@tonic-gate return (0); 5730Sstevel@tonic-gate 5740Sstevel@tonic-gate case M_PUSHF: 5750Sstevel@tonic-gate /* 5760Sstevel@tonic-gate * We pushed our modified EFLAGS (with IF and TF turned off) 5770Sstevel@tonic-gate * onto the stack. Replace the pushed version with our 5780Sstevel@tonic-gate * unmodified one. 5790Sstevel@tonic-gate */ 5800Sstevel@tonic-gate (void) kmdb_dpi_get_register("sp", &sp); 5810Sstevel@tonic-gate 5820Sstevel@tonic-gate if (mdb_tgt_vwrite(mdb.m_target, &oldfl, sizeof (kreg_t), 5830Sstevel@tonic-gate sp) != sizeof (kreg_t)) { 5840Sstevel@tonic-gate warn("failed to update pushed " FLAGS_REG_NAME 5850Sstevel@tonic-gate " at %p after pushfl step\n", (void *)sp); 5860Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */ 5870Sstevel@tonic-gate } 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate /* Go back to using the EFLAGS we were using before the step */ 5900Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, oldfl); 5910Sstevel@tonic-gate return (0); 5920Sstevel@tonic-gate 5930Sstevel@tonic-gate default: 5940Sstevel@tonic-gate /* 5950Sstevel@tonic-gate * The stepped instruction may have altered EFLAGS. We only 5960Sstevel@tonic-gate * really care about the value of IF, and we know the stepped 5970Sstevel@tonic-gate * instruction didn't alter it, so we can simply copy the 5980Sstevel@tonic-gate * pre-step value. We'll also need to turn TF back off. 5990Sstevel@tonic-gate */ 6000Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl); 6010Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, 6020Sstevel@tonic-gate ((fl & ~(KREG_EFLAGS_TF_MASK|KREG_EFLAGS_IF_MASK)) | 6030Sstevel@tonic-gate (oldfl & KREG_EFLAGS_IF_MASK))); 6040Sstevel@tonic-gate return (0); 6050Sstevel@tonic-gate } 6060Sstevel@tonic-gate } 6070Sstevel@tonic-gate 6080Sstevel@tonic-gate /* 6090Sstevel@tonic-gate * The target has already configured the chip for branch step, leaving us to 6100Sstevel@tonic-gate * actually make the machine go. Due to a number of issues involving 6110Sstevel@tonic-gate * the potential alteration of system state via instructions like sti, cli, 6120Sstevel@tonic-gate * pushfl, and popfl, we're going to treat this like a normal system resume. 6130Sstevel@tonic-gate * All CPUs will be released, on the kernel's IDT. Our primary concern is 6140Sstevel@tonic-gate * the alteration/storage of our TF'd EFLAGS via pushfl and popfl. There's no 6150Sstevel@tonic-gate * real workaround - we don't have opcode breakpoints - so the best we can do is 6160Sstevel@tonic-gate * to ensure that the world won't end if someone does bad things to EFLAGS. 6170Sstevel@tonic-gate * 6180Sstevel@tonic-gate * Two things can happen: 6190Sstevel@tonic-gate * 1. EFLAGS.TF may be cleared, either maliciously or via a popfl from saved 6200Sstevel@tonic-gate * state. The CPU will continue execution beyond the branch, and will not 6210Sstevel@tonic-gate * reenter the debugger unless brought/sent in by other means. 6220Sstevel@tonic-gate * 2. Someone may pushlf the TF'd EFLAGS, and may stash a copy of it somewhere. 6230Sstevel@tonic-gate * When the saved version is popfl'd back into place, the debugger will be 6240Sstevel@tonic-gate * re-entered on a single-step trap. 6250Sstevel@tonic-gate */ 6260Sstevel@tonic-gate static void 6270Sstevel@tonic-gate kaif_step_branch(void) 6280Sstevel@tonic-gate { 6290Sstevel@tonic-gate kreg_t fl; 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl); 6320Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, 6330Sstevel@tonic-gate (fl | (1 << KREG_EFLAGS_TF_SHIFT))); 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate kmdb_dpi_resume_master(); 6360Sstevel@tonic-gate 6370Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, fl); 6380Sstevel@tonic-gate } 6390Sstevel@tonic-gate 6400Sstevel@tonic-gate /*ARGSUSED*/ 6410Sstevel@tonic-gate static uintptr_t 6420Sstevel@tonic-gate kaif_call(uintptr_t funcva, uint_t argc, const uintptr_t argv[]) 6430Sstevel@tonic-gate { 6440Sstevel@tonic-gate return (kaif_invoke(funcva, argc, argv)); 6450Sstevel@tonic-gate } 6460Sstevel@tonic-gate 6470Sstevel@tonic-gate static void 648*1234Sjohnlev dump_crumb(kaif_crumb_t *krmp) 6490Sstevel@tonic-gate { 650*1234Sjohnlev kaif_crumb_t krm; 651*1234Sjohnlev 652*1234Sjohnlev if (mdb_vread(&krm, sizeof (kaif_crumb_t), (uintptr_t)krmp) != 653*1234Sjohnlev sizeof (kaif_crumb_t)) { 654*1234Sjohnlev warn("failed to read crumb at %p", krmp); 655*1234Sjohnlev return; 656*1234Sjohnlev } 657*1234Sjohnlev 6580Sstevel@tonic-gate mdb_printf("state: "); 659*1234Sjohnlev switch (krm.krm_cpu_state) { 6600Sstevel@tonic-gate case KAIF_CPU_STATE_MASTER: 6610Sstevel@tonic-gate mdb_printf("M"); 6620Sstevel@tonic-gate break; 6630Sstevel@tonic-gate case KAIF_CPU_STATE_SLAVE: 6640Sstevel@tonic-gate mdb_printf("S"); 6650Sstevel@tonic-gate break; 6660Sstevel@tonic-gate default: 667*1234Sjohnlev mdb_printf("%d", krm.krm_cpu_state); 6680Sstevel@tonic-gate } 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate mdb_printf(" trapno %3d sp %08x flag %d pc %p %A\n", 671*1234Sjohnlev krm.krm_trapno, krm.krm_sp, krm.krm_flag, krm.krm_pc, krm.krm_pc); 6720Sstevel@tonic-gate } 6730Sstevel@tonic-gate 6740Sstevel@tonic-gate static void 6750Sstevel@tonic-gate dump_crumbs(kaif_cpusave_t *save) 6760Sstevel@tonic-gate { 6770Sstevel@tonic-gate int i; 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate for (i = KAIF_NCRUMBS; i > 0; i--) { 6800Sstevel@tonic-gate uint_t idx = (save->krs_curcrumbidx + i) % KAIF_NCRUMBS; 6810Sstevel@tonic-gate dump_crumb(&save->krs_crumbs[idx]); 6820Sstevel@tonic-gate } 6830Sstevel@tonic-gate } 6840Sstevel@tonic-gate 6850Sstevel@tonic-gate static void 6860Sstevel@tonic-gate kaif_dump_crumbs(uintptr_t addr, int cpuid) 6870Sstevel@tonic-gate { 6880Sstevel@tonic-gate int i; 6890Sstevel@tonic-gate 6900Sstevel@tonic-gate if (addr != NULL) { 691*1234Sjohnlev /* dump_crumb will protect us against bogus addresses */ 6920Sstevel@tonic-gate dump_crumb((kaif_crumb_t *)addr); 6930Sstevel@tonic-gate 6940Sstevel@tonic-gate } else if (cpuid != -1) { 695*1234Sjohnlev if (cpuid < 0 || cpuid >= kaif_ncpusave) 6960Sstevel@tonic-gate return; 6970Sstevel@tonic-gate 6980Sstevel@tonic-gate dump_crumbs(&kaif_cpusave[cpuid]); 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate } else { 7010Sstevel@tonic-gate for (i = 0; i < kaif_ncpusave; i++) { 7020Sstevel@tonic-gate kaif_cpusave_t *save = &kaif_cpusave[i]; 7030Sstevel@tonic-gate 7040Sstevel@tonic-gate if (save->krs_cpu_state == KAIF_CPU_STATE_NONE) 7050Sstevel@tonic-gate continue; 7060Sstevel@tonic-gate 7070Sstevel@tonic-gate mdb_printf("%sCPU %d crumbs: (curidx %d)\n", 7080Sstevel@tonic-gate (i == 0 ? "" : "\n"), i, save->krs_curcrumbidx); 7090Sstevel@tonic-gate 7100Sstevel@tonic-gate dump_crumbs(save); 7110Sstevel@tonic-gate } 7120Sstevel@tonic-gate } 7130Sstevel@tonic-gate } 7140Sstevel@tonic-gate 7150Sstevel@tonic-gate static void 7160Sstevel@tonic-gate kaif_modchg_register(void (*func)(struct modctl *, int)) 7170Sstevel@tonic-gate { 7180Sstevel@tonic-gate kaif_modchg_cb = func; 7190Sstevel@tonic-gate } 7200Sstevel@tonic-gate 7210Sstevel@tonic-gate static void 7220Sstevel@tonic-gate kaif_modchg_cancel(void) 7230Sstevel@tonic-gate { 7240Sstevel@tonic-gate ASSERT(kaif_modchg_cb != NULL); 7250Sstevel@tonic-gate 7260Sstevel@tonic-gate kaif_modchg_cb = NULL; 7270Sstevel@tonic-gate } 7280Sstevel@tonic-gate 7290Sstevel@tonic-gate void 7300Sstevel@tonic-gate kaif_mod_loaded(struct modctl *modp) 7310Sstevel@tonic-gate { 7320Sstevel@tonic-gate if (kaif_modchg_cb != NULL) 7330Sstevel@tonic-gate kaif_modchg_cb(modp, 1); 7340Sstevel@tonic-gate } 7350Sstevel@tonic-gate 7360Sstevel@tonic-gate void 7370Sstevel@tonic-gate kaif_mod_unloading(struct modctl *modp) 7380Sstevel@tonic-gate { 7390Sstevel@tonic-gate if (kaif_modchg_cb != NULL) 7400Sstevel@tonic-gate kaif_modchg_cb(modp, 0); 7410Sstevel@tonic-gate } 7420Sstevel@tonic-gate 7430Sstevel@tonic-gate /* 7440Sstevel@tonic-gate * On some processors, we'll need to clear a certain MSR before proceeding into 7450Sstevel@tonic-gate * the debugger. Complicating matters, this MSR must be cleared before we take 7460Sstevel@tonic-gate * any branches. We have patch points in every trap handler, which will cover 7470Sstevel@tonic-gate * all entry paths for master CPUs. We also have a patch point in the slave 7480Sstevel@tonic-gate * entry code. 7490Sstevel@tonic-gate */ 7500Sstevel@tonic-gate static void 7510Sstevel@tonic-gate kaif_msr_add_clrentry(uint_t msr) 7520Sstevel@tonic-gate { 7530Sstevel@tonic-gate #ifdef __amd64 7540Sstevel@tonic-gate uchar_t code[] = { 7550Sstevel@tonic-gate 0x51, 0x50, 0x52, /* pushq %rcx, %rax, %rdx */ 7560Sstevel@tonic-gate 0xb9, 0x00, 0x00, 0x00, 0x00, /* movl $MSRNUM, %ecx */ 7570Sstevel@tonic-gate 0x31, 0xc0, /* clr %eax */ 7580Sstevel@tonic-gate 0x31, 0xd2, /* clr %edx */ 7590Sstevel@tonic-gate 0x0f, 0x30, /* wrmsr */ 7600Sstevel@tonic-gate 0x5a, 0x58, 0x59 /* popq %rdx, %rax, %rcx */ 7610Sstevel@tonic-gate }; 7620Sstevel@tonic-gate uchar_t *patch = &code[4]; 7630Sstevel@tonic-gate #else 7640Sstevel@tonic-gate uchar_t code[] = { 7650Sstevel@tonic-gate 0x60, /* pushal */ 7660Sstevel@tonic-gate 0xb9, 0x00, 0x00, 0x00, 0x00, /* movl $MSRNUM, %ecx */ 7670Sstevel@tonic-gate 0x31, 0xc0, /* clr %eax */ 7680Sstevel@tonic-gate 0x31, 0xd2, /* clr %edx */ 7690Sstevel@tonic-gate 0x0f, 0x30, /* wrmsr */ 7700Sstevel@tonic-gate 0x61 /* popal */ 7710Sstevel@tonic-gate }; 7720Sstevel@tonic-gate uchar_t *patch = &code[2]; 7730Sstevel@tonic-gate #endif 7740Sstevel@tonic-gate 7750Sstevel@tonic-gate bcopy(&msr, patch, sizeof (uint32_t)); 7760Sstevel@tonic-gate 7770Sstevel@tonic-gate kaif_idt_patch((caddr_t)code, sizeof (code)); 7780Sstevel@tonic-gate 7790Sstevel@tonic-gate bcopy(code, &kaif_slave_entry_patch, sizeof (code)); 7800Sstevel@tonic-gate } 7810Sstevel@tonic-gate 7820Sstevel@tonic-gate static void 7830Sstevel@tonic-gate kaif_msr_add_wrexit(uint_t msr, uint64_t *valp) 7840Sstevel@tonic-gate { 7850Sstevel@tonic-gate kaif_msr_wrexit_msr = msr; 7860Sstevel@tonic-gate kaif_msr_wrexit_valp = valp; 7870Sstevel@tonic-gate } 7880Sstevel@tonic-gate 7890Sstevel@tonic-gate static void 7900Sstevel@tonic-gate kaif_msr_add(const kmdb_msr_t *msrs) 7910Sstevel@tonic-gate { 7920Sstevel@tonic-gate kmdb_msr_t *save; 7930Sstevel@tonic-gate int nmsrs, i; 7940Sstevel@tonic-gate 7950Sstevel@tonic-gate ASSERT(kaif_cpusave[0].krs_msr == NULL); 7960Sstevel@tonic-gate 7970Sstevel@tonic-gate for (i = 0; msrs[i].msr_num != 0; i++) { 7980Sstevel@tonic-gate switch (msrs[i].msr_type) { 7990Sstevel@tonic-gate case KMDB_MSR_CLEARENTRY: 8000Sstevel@tonic-gate kaif_msr_add_clrentry(msrs[i].msr_num); 8010Sstevel@tonic-gate break; 8020Sstevel@tonic-gate 8030Sstevel@tonic-gate case KMDB_MSR_WRITEDELAY: 8040Sstevel@tonic-gate kaif_msr_add_wrexit(msrs[i].msr_num, msrs[i].msr_valp); 8050Sstevel@tonic-gate break; 8060Sstevel@tonic-gate } 8070Sstevel@tonic-gate } 8080Sstevel@tonic-gate nmsrs = i + 1; /* we want to copy the terminating kmdb_msr_t too */ 8090Sstevel@tonic-gate 8100Sstevel@tonic-gate save = mdb_zalloc(sizeof (kmdb_msr_t) * nmsrs * kaif_ncpusave, 8110Sstevel@tonic-gate UM_SLEEP); 8120Sstevel@tonic-gate 8130Sstevel@tonic-gate for (i = 0; i < kaif_ncpusave; i++) { 8140Sstevel@tonic-gate bcopy(msrs, &save[nmsrs * i], sizeof (kmdb_msr_t) * nmsrs); 8150Sstevel@tonic-gate kaif_cpusave[i].krs_msr = &save[nmsrs * i]; 8160Sstevel@tonic-gate } 8170Sstevel@tonic-gate } 8180Sstevel@tonic-gate 8190Sstevel@tonic-gate static uint64_t 8200Sstevel@tonic-gate kaif_msr_get(int cpuid, uint_t num) 8210Sstevel@tonic-gate { 822*1234Sjohnlev kaif_cpusave_t *save; 8230Sstevel@tonic-gate kmdb_msr_t *msr; 8240Sstevel@tonic-gate int i; 8250Sstevel@tonic-gate 826*1234Sjohnlev if ((save = kaif_cpuid2save(cpuid)) == NULL) 827*1234Sjohnlev return (-1); /* errno is set for us */ 828*1234Sjohnlev 829*1234Sjohnlev msr = save->krs_msr; 8300Sstevel@tonic-gate 8310Sstevel@tonic-gate for (i = 0; msr[i].msr_num != 0; i++) { 8320Sstevel@tonic-gate if (msr[i].msr_num == num && 8330Sstevel@tonic-gate (msr[i].msr_type & KMDB_MSR_READ)) 8340Sstevel@tonic-gate return (msr[i].msr_val); 8350Sstevel@tonic-gate } 8360Sstevel@tonic-gate 8370Sstevel@tonic-gate return (0); 8380Sstevel@tonic-gate } 8390Sstevel@tonic-gate 8400Sstevel@tonic-gate int 8410Sstevel@tonic-gate kaif_memrange_add(caddr_t base, size_t len) 8420Sstevel@tonic-gate { 8430Sstevel@tonic-gate kaif_memrange_t *mr = &kaif_memranges[kaif_nmemranges]; 8440Sstevel@tonic-gate 8450Sstevel@tonic-gate if (kaif_nmemranges == KAIF_MEMRANGES_MAX) 8460Sstevel@tonic-gate return (set_errno(ENOSPC)); 8470Sstevel@tonic-gate 8480Sstevel@tonic-gate /* 8490Sstevel@tonic-gate * In the unlikely event that someone is stepping through this routine, 8500Sstevel@tonic-gate * we need to make sure that kaif_memranges knows about the new range 8510Sstevel@tonic-gate * before umem gets it. That way the entry code can recognize stacks 8520Sstevel@tonic-gate * allocated from the new region. 8530Sstevel@tonic-gate */ 8540Sstevel@tonic-gate mr->mr_base = base; 8550Sstevel@tonic-gate mr->mr_lim = base + len - 1; 8560Sstevel@tonic-gate kaif_nmemranges++; 8570Sstevel@tonic-gate 8580Sstevel@tonic-gate if (mdb_umem_add(base, len) < 0) { 8590Sstevel@tonic-gate kaif_nmemranges--; 8600Sstevel@tonic-gate return (-1); /* errno is set for us */ 8610Sstevel@tonic-gate } 8620Sstevel@tonic-gate 8630Sstevel@tonic-gate return (0); 8640Sstevel@tonic-gate } 8650Sstevel@tonic-gate 8660Sstevel@tonic-gate void 8670Sstevel@tonic-gate kaif_trap_set_debugger(void) 8680Sstevel@tonic-gate { 8690Sstevel@tonic-gate set_idt(&kaif_idtr); 8700Sstevel@tonic-gate } 8710Sstevel@tonic-gate 8720Sstevel@tonic-gate void 8730Sstevel@tonic-gate kaif_trap_set_saved(kaif_cpusave_t *cpusave) 8740Sstevel@tonic-gate { 8750Sstevel@tonic-gate set_idt(&cpusave->krs_idtr); 8760Sstevel@tonic-gate } 8770Sstevel@tonic-gate 8780Sstevel@tonic-gate static int 8790Sstevel@tonic-gate kaif_init(kmdb_auxv_t *kav) 8800Sstevel@tonic-gate { 8810Sstevel@tonic-gate int i; 8820Sstevel@tonic-gate 8830Sstevel@tonic-gate /* Allocate the per-CPU save areas */ 8840Sstevel@tonic-gate kaif_cpusave = mdb_zalloc(sizeof (kaif_cpusave_t) * kav->kav_ncpu, 8850Sstevel@tonic-gate UM_SLEEP); 8860Sstevel@tonic-gate kaif_ncpusave = kav->kav_ncpu; 8870Sstevel@tonic-gate 8880Sstevel@tonic-gate for (i = 0; i < kaif_ncpusave; i++) { 889*1234Sjohnlev kaif_cpusave_t *save = &kaif_cpusave[i]; 8900Sstevel@tonic-gate 891*1234Sjohnlev save->krs_cpu_id = i; 892*1234Sjohnlev save->krs_curcrumbidx = KAIF_NCRUMBS - 1; 893*1234Sjohnlev save->krs_curcrumb = &save->krs_crumbs[save->krs_curcrumbidx]; 8940Sstevel@tonic-gate } 8950Sstevel@tonic-gate 8960Sstevel@tonic-gate kaif_idt_init(); 8970Sstevel@tonic-gate 8980Sstevel@tonic-gate /* The initial selector set. Updated by the debugger-entry code */ 8990Sstevel@tonic-gate #ifndef __amd64 9000Sstevel@tonic-gate kaif_cs = BOOTCODE_SEL; 9010Sstevel@tonic-gate kaif_ds = kaif_fs = kaif_gs = BOOTFLAT_SEL; 9020Sstevel@tonic-gate #endif 9030Sstevel@tonic-gate 9040Sstevel@tonic-gate kaif_memranges[0].mr_base = kav->kav_dseg; 9050Sstevel@tonic-gate kaif_memranges[0].mr_lim = kav->kav_dseg + kav->kav_dseg_size - 1; 9060Sstevel@tonic-gate kaif_nmemranges = 1; 9070Sstevel@tonic-gate 9080Sstevel@tonic-gate kaif_modchg_cb = NULL; 9090Sstevel@tonic-gate 9100Sstevel@tonic-gate kaif_waptmap = 0; 9110Sstevel@tonic-gate 9120Sstevel@tonic-gate kaif_drreg.dr_ctl = KREG_DRCTL_RESERVED; 9130Sstevel@tonic-gate kaif_drreg.dr_stat = KREG_DRSTAT_RESERVED; 9140Sstevel@tonic-gate 9150Sstevel@tonic-gate kaif_msr_wrexit_msr = 0; 9160Sstevel@tonic-gate kaif_msr_wrexit_valp = NULL; 9170Sstevel@tonic-gate 9180Sstevel@tonic-gate kaif_trap_switch = (kav->kav_flags & KMDB_AUXV_FL_NOTRPSWTCH) == 0; 9190Sstevel@tonic-gate 9200Sstevel@tonic-gate if ((kaif_sys_sysenter = kmdb_kdi_lookup_by_name("unix", 9210Sstevel@tonic-gate "sys_sysenter")) == NULL) 9220Sstevel@tonic-gate return (set_errno(ENOENT)); 9230Sstevel@tonic-gate 9240Sstevel@tonic-gate return (0); 9250Sstevel@tonic-gate } 9260Sstevel@tonic-gate 9270Sstevel@tonic-gate dpi_ops_t kmdb_dpi_ops = { 9280Sstevel@tonic-gate kaif_init, 9290Sstevel@tonic-gate kaif_activate, 9300Sstevel@tonic-gate kaif_deactivate, 9310Sstevel@tonic-gate kaif_enter_mon, 9320Sstevel@tonic-gate kaif_modchg_register, 9330Sstevel@tonic-gate kaif_modchg_cancel, 9340Sstevel@tonic-gate kaif_get_cpu_state, 9350Sstevel@tonic-gate kaif_get_master_cpuid, 9360Sstevel@tonic-gate kaif_get_gregs, 937*1234Sjohnlev kaif_get_register, 938*1234Sjohnlev kaif_set_register, 9390Sstevel@tonic-gate kaif_brkpt_arm, 9400Sstevel@tonic-gate kaif_brkpt_disarm, 9410Sstevel@tonic-gate kaif_wapt_validate, 9420Sstevel@tonic-gate kaif_wapt_reserve, 9430Sstevel@tonic-gate kaif_wapt_release, 9440Sstevel@tonic-gate kaif_wapt_arm, 9450Sstevel@tonic-gate kaif_wapt_disarm, 9460Sstevel@tonic-gate kaif_wapt_match, 9470Sstevel@tonic-gate kaif_step, 9480Sstevel@tonic-gate kaif_step_branch, 9490Sstevel@tonic-gate kaif_call, 9500Sstevel@tonic-gate kaif_dump_crumbs, 9510Sstevel@tonic-gate kaif_memrange_add, 9520Sstevel@tonic-gate kaif_msr_add, 9530Sstevel@tonic-gate kaif_msr_get, 9540Sstevel@tonic-gate }; 955