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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#pragma ident	"%Z%%M%	%I%	%E% SMI"
27
28/*
29 * The KDI, or kernel/debugger interface, is used to allow the kernel and the
30 * debugger to communicate.  These communications take two forms:
31 *
32 *  1. kernel to debugger.  Interfaces of this type are used by the kernel to
33 *     inform the debugger of changes in the state of the system that need to
34 *     be noted by the debugger.  For example, the kernel uses one of these
35 *     interfaces to tell debugger that the set of currently-loaded modules
36 *     has changed.
37 *
38 *  2. debugger to kernel.  Interfaces of this type are used by the debugger
39 *     to extract information from the kernel that would otherwise be difficult
40 *     to get, or to perform services that are specific to the machine being
41 *     used.  An example of the former is the module iterator, which is needed
42 *     to allow symbol resolution, but which needs to resolve symbols prior
43 *     to the iteration.  The latter class include machine-specific or
44 *     cpu-type-specific functions, such as the I-cache flusher.  By directly
45 *     using the kernel versions of these functions, we avoid the need to
46 *     include multiple versions of each function - one per cpu and/or machine -
47 *     in kmdb.
48 */
49
50#include <sys/kdi_impl.h>
51
52#include <kmdb/kmdb_kdi.h>
53#include <kmdb/kmdb_dpi.h>
54#include <kmdb/kmdb_kvm.h>
55#include <kmdb/kmdb_promif.h>
56#include <mdb/mdb_debug.h>
57#include <mdb/mdb_err.h>
58#include <mdb/mdb.h>
59
60static int kdi_unload_request;
61
62typedef struct mod_interp_data {
63	int	(*mid_usercb)(struct modctl *, void *);
64	void	*mid_userarg;
65	jmp_buf mid_pcb;
66	jmp_buf *mid_oldpcb;
67} mod_interp_data_t;
68
69static kmdb_auxv_t *kdi_auxv;
70
71int
72kmdb_kdi_mods_changed(void)
73{
74	return (mdb.m_kdi->kdi_mods_changed());
75}
76
77static int
78kmdb_kdi_mod_interp(struct modctl *mp, void *arg)
79{
80	mod_interp_data_t *mid = arg;
81	int rc;
82
83	kmdb_dpi_restore_fault_hdlr(mid->mid_oldpcb);
84	rc = mid->mid_usercb(mp, mid->mid_userarg);
85	mid->mid_oldpcb = kmdb_dpi_set_fault_hdlr(&mid->mid_pcb);
86
87	return (rc);
88}
89
90/*
91 * We need to protect ourselves against any problems that may occur while
92 * executing the module iterator, currently located in krtld.  If, for
93 * example, one of the next pointers in the module list points to an invalid
94 * address, we don't want kmdb to explode.  As such, we protect ourselves
95 * with the DPI fault-protection routines.  We don't want our fault-protection
96 * callback to protect the callback that the kmdb consumer provided, so we
97 * provide our own interposition callback that removes our fault-protector
98 * before invoking the user's callback.
99 */
100int
101kmdb_kdi_mod_iter(int (*cb)(struct modctl *, void *), void *arg)
102{
103	mod_interp_data_t mid;
104	int rc;
105
106	if (setjmp(mid.mid_pcb) != 0) {
107		/* We took a fault while iterating through the modules */
108		kmdb_dpi_restore_fault_hdlr(mid.mid_oldpcb);
109		return (-1);
110	}
111
112	mid.mid_usercb = cb;
113	mid.mid_userarg = arg;
114	mid.mid_oldpcb = kmdb_dpi_set_fault_hdlr(&mid.mid_pcb);
115
116	rc = mdb.m_kdi->kdi_mod_iter(kmdb_kdi_mod_interp, &mid);
117
118	kmdb_dpi_restore_fault_hdlr(mid.mid_oldpcb);
119
120	return (rc);
121}
122
123int
124kmdb_kdi_mod_isloaded(struct modctl *modp)
125{
126	return (mdb.m_kdi->kdi_mod_isloaded(modp));
127}
128
129int
130kmdb_kdi_mod_haschanged(struct modctl *mc1, struct module *mp1,
131    struct modctl *mc2, struct module *mp2)
132{
133	return (mdb.m_kdi->kdi_mod_haschanged(mc1, mp1, mc2, mp2));
134}
135
136static ssize_t
137kdi_prw(void *buf, size_t nbytes, physaddr_t addr, int (*rw)(caddr_t, size_t,
138    physaddr_t, size_t *))
139{
140	size_t sz;
141	int rc;
142
143	kmdb_dpi_flush_slave_caches();
144	if ((rc = rw(buf, nbytes, addr, &sz)) != 0)
145		return (set_errno(rc));
146
147	return (sz);
148}
149
150ssize_t
151kmdb_kdi_pread(void *buf, size_t nbytes, physaddr_t addr)
152{
153	return (kdi_prw(buf, nbytes, addr, mdb.m_kdi->kdi_pread));
154}
155
156ssize_t
157kmdb_kdi_pwrite(void *buf, size_t nbytes, physaddr_t addr)
158{
159	return (kdi_prw(buf, nbytes, addr, mdb.m_kdi->kdi_pwrite));
160}
161
162void
163kmdb_kdi_flush_caches(void)
164{
165	mdb.m_kdi->kdi_flush_caches();
166}
167
168int
169kmdb_kdi_get_unload_request(void)
170{
171	return (kdi_unload_request);
172}
173
174void
175kmdb_kdi_set_unload_request(void)
176{
177	kdi_unload_request = 1;
178}
179
180int
181kmdb_kdi_get_flags(void)
182{
183	uint_t flags = 0;
184
185	if (mdb.m_flags & MDB_FL_NOCTF)
186		flags |= KMDB_KDI_FL_NOCTF;
187	if (mdb.m_flags & MDB_FL_NOMODS)
188		flags |= KMDB_KDI_FL_NOMODS;
189
190	return (flags);
191}
192
193size_t
194kmdb_kdi_range_is_nontoxic(uintptr_t va, size_t sz, int write)
195{
196	return (mdb.m_kdi->kdi_range_is_nontoxic(va, sz, write));
197}
198
199void
200kmdb_kdi_system_claim(void)
201{
202	(void) kmdb_dpi_call((uintptr_t)mdb.m_kdi->kdi_system_claim, 0, NULL);
203	kmdb_prom_debugger_entry();
204}
205
206void
207kmdb_kdi_system_release(void)
208{
209	kmdb_prom_debugger_exit();
210
211	if (mdb.m_kdi->kdi_system_release != NULL) {
212		(void) kmdb_dpi_call((uintptr_t)mdb.m_kdi->kdi_system_release,
213		    0, NULL);
214	}
215}
216
217struct cons_polledio *
218kmdb_kdi_get_polled_io(void)
219{
220	return (mdb.m_kdi->kdi_get_polled_io());
221}
222
223void
224kmdb_kdi_kmdb_enter(void)
225{
226	mdb.m_kdi->kdi_kmdb_enter();
227}
228
229int
230kmdb_kdi_vtop(uintptr_t va, physaddr_t *pap)
231{
232	jmp_buf pcb, *oldpcb;
233	int rc = 0;
234
235	if (setjmp(pcb) == 0) {
236		int err;
237
238		oldpcb = kmdb_dpi_set_fault_hdlr(&pcb);
239
240		if ((err = mdb.m_kdi->kdi_vtop(va, pap)) != 0)
241			rc = set_errno(err == ENOENT ? EMDB_NOMAP : err);
242	} else {
243		/* We faulted during the translation */
244		rc = set_errno(EMDB_NOMAP);
245	}
246
247	kmdb_dpi_restore_fault_hdlr(oldpcb);
248
249	return (rc);
250}
251
252kdi_dtrace_state_t
253kmdb_kdi_dtrace_get_state(void)
254{
255	return (mdb.m_kdi->kdi_dtrace_get_state());
256}
257
258int
259kmdb_kdi_dtrace_set(int state)
260{
261	int err;
262
263	if ((err = mdb.m_kdi->kdi_dtrace_set(state)) != 0)
264		return (set_errno(err));
265
266	return (0);
267}
268
269/*
270 * This function is to be called only during kmdb initialization, as it
271 * uses the running kernel for symbol translation facilities.
272 */
273uintptr_t
274kmdb_kdi_lookup_by_name(char *modname, char *symname)
275{
276	ASSERT(kmdb_dpi_get_state(NULL) == DPI_STATE_INIT);
277
278	return (kdi_auxv->kav_lookup_by_name(modname, symname));
279}
280
281void
282kmdb_kdi_init(kdi_t *kdi, kmdb_auxv_t *kav)
283{
284	mdb.m_kdi = kdi;
285	mdb.m_pagesize = kav->kav_pagesize;
286
287	kdi_unload_request = 0;
288
289	kdi_auxv = kav;
290
291	kmdb_kdi_init_isadep(kdi, kav);
292}
293
294void
295kmdb_kdi_end_init(void)
296{
297	kdi_auxv = NULL;
298}
299