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
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.
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]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
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.
34 #include <sys/types.h>
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>
49 jmp_buf *kmdb_dpi_fault_pcb
;
50 jmp_buf kmdb_dpi_resume_pcb
;
51 jmp_buf kmdb_dpi_entry_pcb
;
53 static int kmdb_dpi_state
;
54 static int kmdb_dpi_state_why
;
56 uint_t kmdb_dpi_resume_requested
;
57 uint_t kmdb_dpi_switch_target
= (uint_t
)-1;
59 /* Used by the style-specific resume interfaces to signal the driver */
60 void (*kmdb_dpi_wrintr_fire
)(void);
63 kmdb_dpi_init(kmdb_auxv_t
*kav
)
65 kmdb_dpi_state
= DPI_STATE_INIT
;
66 kmdb_dpi_resume_requested
= 0;
67 kmdb_dpi_wrintr_fire
= kav
->kav_wrintr_fire
;
69 mdb
.m_dpi
= &kmdb_dpi_ops
;
70 return (mdb
.m_dpi
->dpo_init(kav
));
75 kmdb_activate(kdi_debugvec_t
**dvecp
, uint_t flags
)
77 mdb
.m_dpi
->dpo_debugger_activate(dvecp
, flags
);
83 mdb
.m_dpi
->dpo_debugger_deactivate();
87 kmdb_dpi_reenter(void)
91 kmdb_kdi_system_claim();
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);
100 fail("kmdb_first_start returned");
104 mdb_dprintf(MDB_DBG_DPI
, "returning to driver - cmd %d%s\n", cmd
,
105 (kmdb_dpi_work_required() ? " (work required)" : ""));
107 kmdb_kdi_system_release();
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
120 kmdb_dpi_enter_mon(void)
122 mdb
.m_dpi
->dpo_enter_mon();
126 kmdb_dpi_modchg_register(void (*func
)(struct modctl
*, int))
128 mdb
.m_dpi
->dpo_modchg_register(func
);
132 kmdb_dpi_modchg_cancel(void)
134 mdb
.m_dpi
->dpo_modchg_cancel();
138 kmdb_dpi_get_cpu_state(int cpuid
)
140 return (mdb
.m_dpi
->dpo_get_cpu_state(cpuid
));
144 kmdb_dpi_get_master_cpuid(void)
146 return (mdb
.m_dpi
->dpo_get_master_cpuid());
149 const mdb_tgt_gregset_t
*
150 kmdb_dpi_get_gregs(int cpuid
)
152 return (mdb
.m_dpi
->dpo_get_gregs(cpuid
));
156 kmdb_dpi_set_fault_hdlr(jmp_buf *jb
)
158 jmp_buf *oldpcb
= kmdb_dpi_fault_pcb
;
160 kmdb_dpi_fault_pcb
= jb
;
166 kmdb_dpi_restore_fault_hdlr(jmp_buf *jb
)
168 (void) kmdb_dpi_set_fault_hdlr(jb
);
172 * Used to tell the driver that it needs to do work after the resume.
174 * CAUTION: This routine may be called *after* mdb_destroy
177 kmdb_dpi_work_required(void)
179 return (kmdb_kdi_get_unload_request() ||
180 !kmdb_wr_driver_notify_isempty());
184 kmdb_dpi_resume_master(void)
186 kmdb_dpi_resume_common(KMDB_DPI_CMD_RESUME_MASTER
);
190 kmdb_dpi_resume(void)
192 kmdb_dpi_resume_common(KMDB_DPI_CMD_RESUME_ALL
);
196 kmdb_dpi_resume_unload(void)
198 kmdb_dpi_resume_common(KMDB_DPI_CMD_RESUME_UNLOAD
);
202 kmdb_dpi_switch_master(int tgt_cpuid
)
204 if (kmdb_dpi_get_cpu_state(tgt_cpuid
) < 0)
205 return (-1); /* errno is set for us */
207 kmdb_dpi_switch_target
= tgt_cpuid
;
208 kmdb_dpi_resume_common(KMDB_DPI_CMD_SWITCH_CPU
);
214 kmdb_dpi_flush_slave_caches(void)
216 kmdb_dpi_resume_common(KMDB_DPI_CMD_FLUSH_CACHES
);
219 typedef struct work_results
{
221 mdb_nv_t res_unloads
;
225 kmdb_dbgnotify_cb(kmdb_wr_t
*wn
, void *arg
)
227 work_results_t
*res
= arg
;
229 switch (WR_TASK(wn
)) {
230 case WNTASK_DMOD_LOAD
: {
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
238 kmdb_wr_load_t
*dlr
= (kmdb_wr_load_t
*)wn
;
240 mdb_dprintf(MDB_DBG_DPI
, "received module load message\n");
242 if (kmdb_module_loaded(dlr
) && res
!= NULL
) {
243 (void) mdb_nv_insert(&res
->res_loads
,
244 strbasename(dlr
->dlr_fname
), NULL
, 0, 0);
248 kmdb_module_load_ack(dlr
);
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
);
256 kmdb_wr_driver_notify(wn
);
260 case WNTASK_DMOD_LOAD_ALL
:
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.
266 ASSERT(WR_ISACK(wn
));
268 mdb_dprintf(MDB_DBG_DPI
, "received module load all ack\n");
270 kmdb_module_load_all_ack(wn
);
273 case WNTASK_DMOD_UNLOAD
: {
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.
280 kmdb_wr_unload_t
*dur
= (kmdb_wr_unload_t
*)wn
;
282 ASSERT(WR_ISACK(dur
));
284 mdb_dprintf(MDB_DBG_DPI
, "received module unload ack\n");
286 if (kmdb_module_unloaded(dur
) && res
!= NULL
) {
287 (void) mdb_nv_insert(&res
->res_unloads
,
288 dur
->dur_modname
, NULL
, 0, 0);
291 /* Done with message */
292 kmdb_module_unload_ack(dur
);
296 case WNTASK_DMOD_PATH_CHANGE
: {
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.
302 kmdb_wr_path_t
*dpth
= (kmdb_wr_path_t
*)wn
;
304 ASSERT(WR_ISACK(dpth
));
306 mdb_dprintf(MDB_DBG_DPI
, "received path change ack\n");
308 kmdb_module_path_ack(dpth
);
313 mdb_warn("Received unknown message type %d from driver\n",
321 print_modules(mdb_nv_t
*mods
)
326 while ((v
= mdb_nv_advance(mods
)) != NULL
)
327 mdb_printf(" %s", mdb_nv_get_name(v
));
331 kmdb_dpi_process_work_queue(void)
335 (void) mdb_nv_create(&res
.res_loads
, UM_SLEEP
);
336 (void) mdb_nv_create(&res
.res_unloads
, UM_SLEEP
);
338 mdb_dprintf(MDB_DBG_DPI
, "processing work queue\n");
339 (void) kmdb_wr_debugger_process(kmdb_dbgnotify_cb
, &res
);
341 if (mdb_nv_size(&res
.res_loads
)) {
342 mdb_printf("Loaded modules: [");
343 print_modules(&res
.res_loads
);
347 if (mdb_nv_size(&res
.res_unloads
)) {
348 mdb_printf("Unloaded modules: [");
349 print_modules(&res
.res_unloads
);
353 mdb_nv_destroy(&res
.res_loads
);
354 mdb_nv_destroy(&res
.res_unloads
);
360 return (mdb
.m_dpi
->dpo_step());
364 kmdb_dpi_call(uintptr_t func
, uint_t argc
, const uintptr_t *argv
)
366 return (mdb
.m_dpi
->dpo_call(func
, argc
, argv
));
370 kmdb_dpi_brkpt_arm(uintptr_t addr
, mdb_instr_t
*instrp
)
374 if ((rc
= mdb
.m_dpi
->dpo_brkpt_arm(addr
, instrp
)) < 0)
375 mdb_warn("failed to arm breakpoint at %a", addr
);
377 mdb_dprintf(MDB_DBG_DPI
, "brkpt armed at %p %A\n", (void *)addr
, addr
);
383 kmdb_dpi_brkpt_disarm(uintptr_t addr
, mdb_instr_t instrp
)
387 if ((rc
= mdb
.m_dpi
->dpo_brkpt_disarm(addr
, instrp
)) < 0)
388 mdb_warn("failed to disarm breakpoint at %a", addr
);
390 mdb_dprintf(MDB_DBG_DPI
, "brkpt disarmed at %p %A\n", (void *)addr
,
397 kmdb_dpi_wapt_validate(kmdb_wapt_t
*wp
)
399 if (mdb
.m_dpi
->dpo_wapt_validate(wp
) < 0)
400 return (-1); /* errno is set for us */
406 kmdb_dpi_wapt_reserve(kmdb_wapt_t
*wp
)
408 if (mdb
.m_dpi
->dpo_wapt_reserve(wp
) < 0)
409 return (-1); /* errno is set for us */
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
);
418 kmdb_dpi_wapt_release(kmdb_wapt_t
*wp
)
420 mdb
.m_dpi
->dpo_wapt_release(wp
);
424 kmdb_dpi_wapt_arm(kmdb_wapt_t
*wp
)
426 mdb
.m_dpi
->dpo_wapt_arm(wp
);
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
);
433 kmdb_dpi_wapt_disarm(kmdb_wapt_t
*wp
)
435 mdb
.m_dpi
->dpo_wapt_disarm(wp
);
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
);
442 kmdb_dpi_wapt_match(kmdb_wapt_t
*wp
)
444 return (mdb
.m_dpi
->dpo_wapt_match(wp
));
448 kmdb_dpi_set_state(int state
, int why
)
450 if (kmdb_dpi_state
!= DPI_STATE_LOST
) {
451 mdb_dprintf(MDB_DBG_DPI
, "dpi_set_state %d why %d\n",
454 kmdb_dpi_state
= state
;
455 kmdb_dpi_state_why
= why
;
460 kmdb_dpi_get_state(int *whyp
)
463 *whyp
= kmdb_dpi_state_why
;
465 return (kmdb_dpi_state
);
469 kmdb_dpi_dump_crumbs(uintptr_t addr
, int cpuid
)
471 mdb
.m_dpi
->dpo_dump_crumbs(addr
, cpuid
);