1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * The DPI, or debugger/PROM interface, is used to isolate the debugger from the 31 * means by which we use the PROM to control the machine. 32 */ 33 34 #include <sys/types.h> 35 #include <setjmp.h> 36 37 #include <kmdb/kmdb_dpi_impl.h> 38 #include <kmdb/kmdb_kdi.h> 39 #include <kmdb/kmdb_auxv.h> 40 #include <kmdb/kmdb_wr_impl.h> 41 #include <kmdb/kmdb_module.h> 42 #include <kmdb/kmdb_start.h> 43 #include <kmdb/kmdb_asmutil.h> 44 #include <mdb/mdb_debug.h> 45 #include <mdb/mdb_err.h> 46 #include <mdb/mdb_string.h> 47 #include <mdb/mdb.h> 48 49 jmp_buf *kmdb_dpi_fault_pcb; 50 jmp_buf kmdb_dpi_resume_pcb; 51 jmp_buf kmdb_dpi_entry_pcb; 52 53 static int kmdb_dpi_state; 54 static int kmdb_dpi_state_why; 55 56 uint_t kmdb_dpi_resume_requested; 57 uint_t kmdb_dpi_switch_target = (uint_t)-1; 58 59 /* Used by the style-specific resume interfaces to signal the driver */ 60 void (*kmdb_dpi_wrintr_fire)(void); 61 62 int 63 kmdb_dpi_init(kmdb_auxv_t *kav) 64 { 65 kmdb_dpi_state = DPI_STATE_INIT; 66 kmdb_dpi_resume_requested = 0; 67 kmdb_dpi_wrintr_fire = kav->kav_wrintr_fire; 68 69 mdb.m_dpi = &kmdb_dpi_ops; 70 return (mdb.m_dpi->dpo_init(kav)); 71 } 72 73 /*ARGSUSED1*/ 74 void 75 kmdb_activate(kdi_debugvec_t **dvecp, uint_t flags) 76 { 77 mdb.m_dpi->dpo_debugger_activate(dvecp, flags); 78 } 79 80 void 81 kmdb_deactivate(void) 82 { 83 mdb.m_dpi->dpo_debugger_deactivate(); 84 } 85 86 int 87 kmdb_dpi_reenter(void) 88 { 89 int cmd; 90 91 kmdb_kdi_system_claim(); 92 93 if ((cmd = setjmp(kmdb_dpi_entry_pcb)) == 0) { 94 /* Direct entry from the driver */ 95 if (kmdb_dpi_resume_requested) 96 longjmp(kmdb_dpi_resume_pcb, 1); 97 98 kmdb_first_start(); 99 100 fail("kmdb_first_start returned"); 101 /*NOTREACHED*/ 102 } 103 104 mdb_dprintf(MDB_DBG_DPI, "returning to driver - cmd %d%s\n", cmd, 105 (kmdb_dpi_work_required() ? " (work required)" : "")); 106 107 kmdb_kdi_system_release(); 108 109 membar_producer(); 110 111 /* 112 * The debugger wants us to do something - it returned a command 113 * via the setjmp(). The driver will know what to do with the 114 * command. 115 */ 116 return (cmd); 117 } 118 119 void 120 kmdb_dpi_enter_mon(void) 121 { 122 mdb.m_dpi->dpo_enter_mon(); 123 } 124 125 void 126 kmdb_dpi_modchg_register(void (*func)(struct modctl *, int)) 127 { 128 mdb.m_dpi->dpo_modchg_register(func); 129 } 130 131 void 132 kmdb_dpi_modchg_cancel(void) 133 { 134 mdb.m_dpi->dpo_modchg_cancel(); 135 } 136 137 int 138 kmdb_dpi_get_cpu_state(int cpuid) 139 { 140 return (mdb.m_dpi->dpo_get_cpu_state(cpuid)); 141 } 142 143 int 144 kmdb_dpi_get_master_cpuid(void) 145 { 146 return (mdb.m_dpi->dpo_get_master_cpuid()); 147 } 148 149 const mdb_tgt_gregset_t * 150 kmdb_dpi_get_gregs(int cpuid) 151 { 152 return (mdb.m_dpi->dpo_get_gregs(cpuid)); 153 } 154 155 jmp_buf * 156 kmdb_dpi_set_fault_hdlr(jmp_buf *jb) 157 { 158 jmp_buf *oldpcb = kmdb_dpi_fault_pcb; 159 160 kmdb_dpi_fault_pcb = jb; 161 162 return (oldpcb); 163 } 164 165 void 166 kmdb_dpi_restore_fault_hdlr(jmp_buf *jb) 167 { 168 (void) kmdb_dpi_set_fault_hdlr(jb); 169 } 170 171 /* 172 * Used to tell the driver that it needs to do work after the resume. 173 * 174 * CAUTION: This routine may be called *after* mdb_destroy 175 */ 176 int 177 kmdb_dpi_work_required(void) 178 { 179 return (kmdb_kdi_get_unload_request() || 180 !kmdb_wr_driver_notify_isempty()); 181 } 182 183 void 184 kmdb_dpi_resume_master(void) 185 { 186 kmdb_dpi_resume_common(KMDB_DPI_CMD_RESUME_MASTER); 187 } 188 189 void 190 kmdb_dpi_resume(void) 191 { 192 kmdb_dpi_resume_common(KMDB_DPI_CMD_RESUME_ALL); 193 } 194 195 void 196 kmdb_dpi_resume_unload(void) 197 { 198 kmdb_dpi_resume_common(KMDB_DPI_CMD_RESUME_UNLOAD); 199 } 200 201 int 202 kmdb_dpi_switch_master(int tgt_cpuid) 203 { 204 if (kmdb_dpi_get_cpu_state(tgt_cpuid) < 0) 205 return (-1); /* errno is set for us */ 206 207 kmdb_dpi_switch_target = tgt_cpuid; 208 kmdb_dpi_resume_common(KMDB_DPI_CMD_SWITCH_CPU); 209 210 return (0); 211 } 212 213 void 214 kmdb_dpi_flush_slave_caches(void) 215 { 216 kmdb_dpi_resume_common(KMDB_DPI_CMD_FLUSH_CACHES); 217 } 218 219 typedef struct work_results { 220 mdb_nv_t res_loads; 221 mdb_nv_t res_unloads; 222 } work_results_t; 223 224 static int 225 kmdb_dbgnotify_cb(kmdb_wr_t *wn, void *arg) 226 { 227 work_results_t *res = arg; 228 229 switch (WR_TASK(wn)) { 230 case WNTASK_DMOD_LOAD: { 231 /* 232 * If this is an ack, the driver finished processing a load we 233 * requested. We process it and free the message. If this 234 * isn't an ack, then it's a driver-initiated load. We process 235 * the message, and send it back as an ack so the driver can 236 * free it. 237 */ 238 kmdb_wr_load_t *dlr = (kmdb_wr_load_t *)wn; 239 240 mdb_dprintf(MDB_DBG_DPI, "received module load message\n"); 241 242 if (kmdb_module_loaded(dlr) && res != NULL) { 243 (void) mdb_nv_insert(&res->res_loads, 244 strbasename(dlr->dlr_fname), NULL, 0, 0); 245 } 246 247 if (WR_ISACK(dlr)) { 248 kmdb_module_load_ack(dlr); 249 return (0); 250 } 251 252 /* Send it back as an ack */ 253 mdb_dprintf(MDB_DBG_DPI, "Sending load request for %s back " 254 "as an ack\n", dlr->dlr_fname); 255 WR_ACK(wn); 256 kmdb_wr_driver_notify(wn); 257 return (0); 258 } 259 260 case WNTASK_DMOD_LOAD_ALL: 261 /* 262 * We initiated the load-all, so this must be an ack. The 263 * individual module load messages will arrive separately - 264 * there's no need to do anything further with this message. 265 */ 266 ASSERT(WR_ISACK(wn)); 267 268 mdb_dprintf(MDB_DBG_DPI, "received module load all ack\n"); 269 270 kmdb_module_load_all_ack(wn); 271 return (0); 272 273 case WNTASK_DMOD_UNLOAD: { 274 /* 275 * The debugger received an unload message. The driver isn't 276 * supposed to initiate unloads, so we shouldn't see anything 277 * but acks. We tell the dmod subsystem that the module has 278 * been unloaded, and we free the message. 279 */ 280 kmdb_wr_unload_t *dur = (kmdb_wr_unload_t *)wn; 281 282 ASSERT(WR_ISACK(dur)); 283 284 mdb_dprintf(MDB_DBG_DPI, "received module unload ack\n"); 285 286 if (kmdb_module_unloaded(dur) && res != NULL) { 287 (void) mdb_nv_insert(&res->res_unloads, 288 dur->dur_modname, NULL, 0, 0); 289 } 290 291 /* Done with message */ 292 kmdb_module_unload_ack(dur); 293 return (0); 294 } 295 296 case WNTASK_DMOD_PATH_CHANGE: { 297 /* 298 * The debugger received a path change message. The driver 299 * can't initiate these, so it must be an acknowledgement. 300 * There's no processing to be done, so just free the message. 301 */ 302 kmdb_wr_path_t *dpth = (kmdb_wr_path_t *)wn; 303 304 ASSERT(WR_ISACK(dpth)); 305 306 mdb_dprintf(MDB_DBG_DPI, "received path change ack\n"); 307 308 kmdb_module_path_ack(dpth); 309 return (0); 310 } 311 312 default: 313 mdb_warn("Received unknown message type %d from driver\n", 314 wn->wn_task); 315 /* Ignore it */ 316 return (0); 317 } 318 } 319 320 static void 321 print_modules(mdb_nv_t *mods) 322 { 323 mdb_var_t *v; 324 325 mdb_nv_rewind(mods); 326 while ((v = mdb_nv_advance(mods)) != NULL) 327 mdb_printf(" %s", mdb_nv_get_name(v)); 328 } 329 330 void 331 kmdb_dpi_process_work_queue(void) 332 { 333 work_results_t res; 334 335 (void) mdb_nv_create(&res.res_loads, UM_SLEEP); 336 (void) mdb_nv_create(&res.res_unloads, UM_SLEEP); 337 338 mdb_dprintf(MDB_DBG_DPI, "processing work queue\n"); 339 (void) kmdb_wr_debugger_process(kmdb_dbgnotify_cb, &res); 340 341 if (mdb_nv_size(&res.res_loads)) { 342 mdb_printf("Loaded modules: ["); 343 print_modules(&res.res_loads); 344 mdb_printf(" ]\n"); 345 } 346 347 if (mdb_nv_size(&res.res_unloads)) { 348 mdb_printf("Unloaded modules: ["); 349 print_modules(&res.res_unloads); 350 mdb_printf(" ]\n"); 351 } 352 353 mdb_nv_destroy(&res.res_loads); 354 mdb_nv_destroy(&res.res_unloads); 355 } 356 357 int 358 kmdb_dpi_step(void) 359 { 360 return (mdb.m_dpi->dpo_step()); 361 } 362 363 uintptr_t 364 kmdb_dpi_call(uintptr_t func, uint_t argc, const uintptr_t *argv) 365 { 366 return (mdb.m_dpi->dpo_call(func, argc, argv)); 367 } 368 369 int 370 kmdb_dpi_brkpt_arm(uintptr_t addr, mdb_instr_t *instrp) 371 { 372 int rc; 373 374 if ((rc = mdb.m_dpi->dpo_brkpt_arm(addr, instrp)) < 0) 375 mdb_warn("failed to arm breakpoint at %a", addr); 376 377 mdb_dprintf(MDB_DBG_DPI, "brkpt armed at %p %A\n", (void *)addr, addr); 378 379 return (rc); 380 } 381 382 int 383 kmdb_dpi_brkpt_disarm(uintptr_t addr, mdb_instr_t instrp) 384 { 385 int rc; 386 387 if ((rc = mdb.m_dpi->dpo_brkpt_disarm(addr, instrp)) < 0) 388 mdb_warn("failed to disarm breakpoint at %a", addr); 389 390 mdb_dprintf(MDB_DBG_DPI, "brkpt disarmed at %p %A\n", (void *)addr, 391 addr); 392 393 return (rc); 394 } 395 396 int 397 kmdb_dpi_wapt_validate(kmdb_wapt_t *wp) 398 { 399 if (mdb.m_dpi->dpo_wapt_validate(wp) < 0) 400 return (-1); /* errno is set for us */ 401 402 return (0); 403 } 404 405 int 406 kmdb_dpi_wapt_reserve(kmdb_wapt_t *wp) 407 { 408 if (mdb.m_dpi->dpo_wapt_reserve(wp) < 0) 409 return (-1); /* errno is set for us */ 410 411 mdb_dprintf(MDB_DBG_DPI, "wapt reserve type %d at %p, priv %p\n", 412 wp->wp_type, (void *)wp->wp_addr, wp->wp_priv); 413 414 return (0); 415 } 416 417 void 418 kmdb_dpi_wapt_release(kmdb_wapt_t *wp) 419 { 420 mdb.m_dpi->dpo_wapt_release(wp); 421 } 422 423 void 424 kmdb_dpi_wapt_arm(kmdb_wapt_t *wp) 425 { 426 mdb.m_dpi->dpo_wapt_arm(wp); 427 428 mdb_dprintf(MDB_DBG_DPI, "wapt armed at %p (type %d, priv %p)\n", 429 (void *)wp->wp_addr, wp->wp_type, wp->wp_priv); 430 } 431 432 void 433 kmdb_dpi_wapt_disarm(kmdb_wapt_t *wp) 434 { 435 mdb.m_dpi->dpo_wapt_disarm(wp); 436 437 mdb_dprintf(MDB_DBG_DPI, "wapt disarmed at %p (type %d, priv %p)\n", 438 (void *)wp->wp_addr, wp->wp_type, wp->wp_priv); 439 } 440 441 int 442 kmdb_dpi_wapt_match(kmdb_wapt_t *wp) 443 { 444 return (mdb.m_dpi->dpo_wapt_match(wp)); 445 } 446 447 void 448 kmdb_dpi_set_state(int state, int why) 449 { 450 if (kmdb_dpi_state != DPI_STATE_LOST) { 451 mdb_dprintf(MDB_DBG_DPI, "dpi_set_state %d why %d\n", 452 state, why); 453 454 kmdb_dpi_state = state; 455 kmdb_dpi_state_why = why; 456 } 457 } 458 459 int 460 kmdb_dpi_get_state(int *whyp) 461 { 462 if (whyp != NULL) 463 *whyp = kmdb_dpi_state_why; 464 465 return (kmdb_dpi_state); 466 } 467 468 void 469 kmdb_dpi_dump_crumbs(uintptr_t addr, int cpuid) 470 { 471 mdb.m_dpi->dpo_dump_crumbs(addr, cpuid); 472 } 473