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 * Implements the kernel side of the debugger/kernel work queue.
30 */
31
32 #include <kmdb/kmdb_kdi.h>
33 #include <kmdb/kctl/kctl.h>
34 #include <kmdb/kctl/kctl_wr.h>
35
36 #include <sys/proc.h>
37 #include <sys/disp.h>
38 #include <sys/kdi_impl.h>
39 #include <sys/callb.h>
40
41 #define KCTL_WR_PROCESS_NORMAL (void *)0
42 #define KCTL_WR_PROCESS_UNLOADING (void *)1
43
44 /*
45 * Processes events from the debugger -> driver notification queue. Returns
46 * 1 if the debugger should be awakened after the queue has been processed.
47 */
48 static int
kctl_wr_process_cb(kmdb_wr_t * wn,void * arg)49 kctl_wr_process_cb(kmdb_wr_t *wn, void *arg)
50 {
51 int unloading = (arg == KCTL_WR_PROCESS_UNLOADING);
52
53 switch (WR_TASK(wn)) {
54 case WNTASK_DMOD_LOAD: {
55 /*
56 * If this is an ack, then we're getting back a message from a
57 * load we initiated. Free it. If it's not an ack, we process
58 * the message (attempt to load the requested module) and send
59 * an ack back to the debugger.
60 */
61 kmdb_wr_load_t *dlr = (kmdb_wr_load_t *)wn;
62
63 if (WR_ISACK(dlr)) {
64 kctl_dprintf("received ack for dmod load of %s",
65 dlr->dlr_fname);
66 kctl_dmod_load_ack(dlr);
67 return (0);
68 } else
69 kctl_dprintf("received dmod load request %s",
70 dlr->dlr_fname);
71
72 if (unloading) {
73 /*
74 * If the user didn't wait for all dmods to load before
75 * she triggered the debugger unload, we may have some
76 * dmod load requests on the queue in front of the
77 * blizzard of dmod unload requests that the debugger
78 * will generate as part of its unload. The debugger
79 * won't have generated unloads for pending dmods, so
80 * we can safely ignore the load requests.
81 */
82 kctl_dprintf("skipping load of dmod %s due to "
83 "in-process unload");
84 } else
85 (void) kctl_dmod_load(dlr); /* dlr will have errno */
86
87 WR_ACK(dlr);
88 kmdb_wr_debugger_notify(dlr);
89 return (1);
90 }
91
92 case WNTASK_DMOD_LOAD_ALL:
93 /*
94 * We don't initiate all-module loads, so this can't be an
95 * ack. We process the load-all, and send the message back
96 * to the driver as an ack.
97 */
98 ASSERT(!WR_ISACK(wn));
99
100 kctl_dprintf("received request to load all dmods");
101
102 (void) kctl_dmod_load_all();
103
104 WR_ACK(wn);
105 kmdb_wr_debugger_notify(wn);
106 return (1);
107
108 case WNTASK_DMOD_UNLOAD: {
109 /*
110 * The driver received an unload request. We don't initiate
111 * unloads, so this can't be an ack. We process the unload,
112 * and send the message back to the driver as an ack.
113 */
114 kmdb_wr_unload_t *dur = (kmdb_wr_unload_t *)wn;
115
116 ASSERT(!WR_ISACK(dur));
117 ASSERT(kctl.kctl_boot_ops == NULL);
118
119 kctl_dprintf("received dmod unload message %s",
120 dur->dur_modname);
121
122 kctl_dmod_unload(dur);
123
124 WR_ACK(dur);
125 kmdb_wr_debugger_notify(dur);
126 return (1);
127 }
128
129 case WNTASK_DMOD_PATH_CHANGE: {
130 /*
131 * We don't initiate path changes, so this can't be an ack.
132 * This request type differs from the others in that we only
133 * return it (as an ack) when we're done with it. We're only
134 * done with it when we receive another one, or when the
135 * debugger is unloading.
136 */
137 kmdb_wr_path_t *pth = (kmdb_wr_path_t *)wn;
138 kmdb_wr_path_t *opth;
139
140 ASSERT(!WR_ISACK(pth));
141
142 kctl_dprintf("received path change message");
143
144 if ((opth = kctl_dmod_path_set(pth)) != NULL) {
145 /* We have an old path request to return */
146 WR_ACK(opth);
147 kmdb_wr_debugger_notify(opth);
148
149 /*
150 * The debugger can process the returned path change
151 * request at its leisure
152 */
153 return (0);
154 }
155
156 /* Nothing to do */
157 return (0);
158 }
159
160 default:
161 cmn_err(CE_WARN, "Received unknown work request %d from kmdb\n",
162 wn->wn_task);
163 /* Drop message */
164 return (0);
165 }
166
167 /*NOTREACHED*/
168 }
169
170 int
kctl_wr_process(void)171 kctl_wr_process(void)
172 {
173 return (kmdb_wr_driver_process(kctl_wr_process_cb,
174 KCTL_WR_PROCESS_NORMAL));
175 }
176
177 /*
178 * Catches the "work to do" soft interrupt, and passes the notification along
179 * to the worker thread.
180 */
181 /*ARGSUSED*/
182 void
kctl_wrintr(void)183 kctl_wrintr(void)
184 {
185 kctl.kctl_wr_avail = 0;
186
187 sema_v(&kctl.kctl_wr_avail_sem);
188 }
189
190 /*
191 * This routine is called by the debugger while the world is resuming.
192 */
193 void
kctl_wrintr_fire(void)194 kctl_wrintr_fire(void)
195 {
196 kctl.kctl_wr_avail = 1;
197
198 kdi_softcall(kctl_wrintr);
199 }
200
201 /*
202 * Given the possibility of asynchronous unload, the locking semantics are
203 * somewhat tricky. See kctl_main.c
204 */
205 /*ARGSUSED*/
206 static void
kctl_wr_thread(void * arg)207 kctl_wr_thread(void *arg)
208 {
209 callb_cpr_t cprinfo;
210 kmutex_t cprlock;
211
212 mutex_init(&cprlock, NULL, MUTEX_DEFAULT, NULL);
213 CALLB_CPR_INIT(&cprinfo, &cprlock, callb_generic_cpr, "kmdb work");
214
215 for (;;) {
216 /*
217 * XXX what should I do here for panic? It'll spin unless I
218 * can figure out a way to park it. Presumably I don't want to
219 * let it exit.
220 */
221 mutex_enter(&cprlock);
222 CALLB_CPR_SAFE_BEGIN(&cprinfo);
223 mutex_exit(&cprlock);
224
225 sema_p(&kctl.kctl_wr_avail_sem);
226
227 mutex_enter(&cprlock);
228 CALLB_CPR_SAFE_END(&cprinfo, &cprlock);
229 mutex_exit(&cprlock);
230
231 kctl_dprintf("kctl worker thread - waking up");
232
233 if (kmdb_kdi_get_unload_request() ||
234 kctl.kctl_wr_state != KCTL_WR_ST_RUN) {
235 /*
236 * We've either got a debugger-initiated unload (if
237 * unload_request returned true), or we're stopping due
238 * to an error discovered by the driver (if
239 * kctl_worker_run is no longer non-zero). Start
240 * cleaning up.
241 */
242
243 /*
244 * The debugger has already deactivated itself, and will
245 * have dumped a bunch of stuff on the queue. We need
246 * to process it before exiting.
247 */
248 (void) kmdb_wr_driver_process(kctl_wr_process_cb,
249 KCTL_WR_PROCESS_UNLOADING);
250 break;
251 }
252
253 /*
254 * A non-zero return means we've passed messages back to the
255 * debugger for processing, so we need to wake the debugger up.
256 */
257 if (kctl_wr_process() > 0)
258 kmdb_kdi_kmdb_enter();
259 }
260
261 /*
262 * NULL out the dmod search path, so we can send the current one back
263 * to the debugger. XXX this should probably be somewhere else.
264 */
265 kctl_dmod_path_reset();
266
267 /*
268 * The debugger will send us unload notifications for each dmod that it
269 * noticed. If, for example, the debugger is unloaded before the first
270 * start, it won't have noticed any of the dmods we loaded. We'll need
271 * to initiate the unloads ourselves.
272 */
273 kctl_dmod_unload_all();
274
275 kctl.kctl_wr_state = KCTL_WR_ST_STOPPED;
276
277 /*
278 * Must be last, as it concludes by setting state to INACTIVE. The
279 * kctl data structure must not be accessed by this thread after that
280 * point.
281 */
282 kctl_cleanup();
283
284 mutex_enter(&cprlock);
285 CALLB_CPR_EXIT(&cprinfo);
286 mutex_destroy(&cprlock);
287 }
288
289 void
kctl_wr_thr_start(void)290 kctl_wr_thr_start(void)
291 {
292 kctl.kctl_wr_avail = 0;
293 kctl.kctl_wr_state = KCTL_WR_ST_RUN;
294 kctl.kctl_wr_thr = thread_create(NULL, 0, kctl_wr_thread, NULL, 0, &p0,
295 TS_RUN, minclsyspri);
296 }
297
298 void
kctl_wr_thr_stop(void)299 kctl_wr_thr_stop(void)
300 {
301 ASSERT(kctl.kctl_wr_state == KCTL_WR_ST_RUN);
302 kctl.kctl_wr_state = KCTL_WR_ST_STOP;
303 sema_v(&kctl.kctl_wr_avail_sem);
304 }
305
306 void
kctl_wr_thr_join(void)307 kctl_wr_thr_join(void)
308 {
309 thread_join(kctl.kctl_wr_thr->t_did);
310 }
311