xref: /openbmc/qemu/chardev/char-mux.c (revision 5ae3ec63)
1 /*
2  * QEMU System Emulator
3  *
4  * Copyright (c) 2003-2008 Fabrice Bellard
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 
25 #include "qemu/osdep.h"
26 #include "qapi/error.h"
27 #include "qemu/module.h"
28 #include "qemu/option.h"
29 #include "qemu/bitops.h"
30 #include "chardev/char.h"
31 #include "sysemu/block-backend.h"
32 #include "qapi/qapi-commands-control.h"
33 #include "chardev-internal.h"
34 
35 /* MUX driver for serial I/O splitting */
36 
37 /*
38  * Set to false by suspend_mux_open.  Open events are delayed until
39  * resume_mux_open.  Usually suspend_mux_open is called before
40  * command line processing and resume_mux_open afterwards.
41  */
42 static bool muxes_opened = true;
43 
44 /* Called with chr_write_lock held.  */
45 static int mux_chr_write(Chardev *chr, const uint8_t *buf, int len)
46 {
47     MuxChardev *d = MUX_CHARDEV(chr);
48     int ret;
49     if (!d->timestamps) {
50         ret = qemu_chr_fe_write(&d->chr, buf, len);
51     } else {
52         int i;
53 
54         ret = 0;
55         for (i = 0; i < len; i++) {
56             if (d->linestart) {
57                 char buf1[64];
58                 int64_t ti;
59                 int secs;
60 
61                 ti = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
62                 if (d->timestamps_start == -1) {
63                     d->timestamps_start = ti;
64                 }
65                 ti -= d->timestamps_start;
66                 secs = ti / 1000;
67                 snprintf(buf1, sizeof(buf1),
68                          "[%02d:%02d:%02d.%03d] ",
69                          secs / 3600,
70                          (secs / 60) % 60,
71                          secs % 60,
72                          (int)(ti % 1000));
73                 /* XXX this blocks entire thread. Rewrite to use
74                  * qemu_chr_fe_write and background I/O callbacks */
75                 qemu_chr_fe_write_all(&d->chr,
76                                       (uint8_t *)buf1, strlen(buf1));
77                 d->linestart = false;
78             }
79             ret += qemu_chr_fe_write(&d->chr, buf + i, 1);
80             if (buf[i] == '\n') {
81                 d->linestart = true;
82             }
83         }
84     }
85     return ret;
86 }
87 
88 static const char * const mux_help[] = {
89     "% h    print this help\n\r",
90     "% x    exit emulator\n\r",
91     "% s    save disk data back to file (if -snapshot)\n\r",
92     "% t    toggle console timestamps\n\r",
93     "% b    send break (magic sysrq)\n\r",
94     "% c    switch between console and monitor\n\r",
95     "% %  sends %\n\r",
96     NULL
97 };
98 
99 int term_escape_char = 0x01; /* ctrl-a is used for escape */
100 static void mux_print_help(Chardev *chr)
101 {
102     int i, j;
103     char ebuf[15] = "Escape-Char";
104     char cbuf[50] = "\n\r";
105 
106     if (term_escape_char > 0 && term_escape_char < 26) {
107         snprintf(cbuf, sizeof(cbuf), "\n\r");
108         snprintf(ebuf, sizeof(ebuf), "C-%c", term_escape_char - 1 + 'a');
109     } else {
110         snprintf(cbuf, sizeof(cbuf),
111                  "\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r",
112                  term_escape_char);
113     }
114     /* XXX this blocks entire thread. Rewrite to use
115      * qemu_chr_fe_write and background I/O callbacks */
116     qemu_chr_write_all(chr, (uint8_t *)cbuf, strlen(cbuf));
117     for (i = 0; mux_help[i] != NULL; i++) {
118         for (j = 0; mux_help[i][j] != '\0'; j++) {
119             if (mux_help[i][j] == '%') {
120                 qemu_chr_write_all(chr, (uint8_t *)ebuf, strlen(ebuf));
121             } else {
122                 qemu_chr_write_all(chr, (uint8_t *)&mux_help[i][j], 1);
123             }
124         }
125     }
126 }
127 
128 static void mux_chr_send_event(MuxChardev *d, unsigned int mux_nr,
129                                QEMUChrEvent event)
130 {
131     CharBackend *be = d->backends[mux_nr];
132 
133     if (be && be->chr_event) {
134         be->chr_event(be->opaque, event);
135     }
136 }
137 
138 static void mux_chr_be_event(Chardev *chr, QEMUChrEvent event)
139 {
140     MuxChardev *d = MUX_CHARDEV(chr);
141 
142     if (d->focus != -1) {
143         mux_chr_send_event(d, d->focus, event);
144     }
145 }
146 
147 static int mux_proc_byte(Chardev *chr, MuxChardev *d, int ch)
148 {
149     if (d->term_got_escape) {
150         d->term_got_escape = false;
151         if (ch == term_escape_char) {
152             goto send_char;
153         }
154         switch (ch) {
155         case '?':
156         case 'h':
157             mux_print_help(chr);
158             break;
159         case 'x':
160             {
161                  const char *term =  "QEMU: Terminated\n\r";
162                  qemu_chr_write_all(chr, (uint8_t *)term, strlen(term));
163                  qmp_quit(NULL);
164                  break;
165             }
166         case 's':
167             blk_commit_all();
168             break;
169         case 'b':
170             qemu_chr_be_event(chr, CHR_EVENT_BREAK);
171             break;
172         case 'c': {
173             unsigned int bit;
174 
175             /* Handler registered with first fe */
176             assert(d->mux_bitset != 0);
177             /* Switch to the next registered device */
178             bit = find_next_bit(&d->mux_bitset, MAX_MUX, d->focus + 1);
179             if (bit >= MAX_MUX) {
180                 bit = find_next_bit(&d->mux_bitset, MAX_MUX, 0);
181             }
182             mux_set_focus(chr, bit);
183             break;
184         } case 't':
185             d->timestamps = !d->timestamps;
186             d->timestamps_start = -1;
187             d->linestart = false;
188             break;
189         }
190     } else if (ch == term_escape_char) {
191         d->term_got_escape = true;
192     } else {
193     send_char:
194         return 1;
195     }
196     return 0;
197 }
198 
199 static void mux_chr_accept_input(Chardev *chr)
200 {
201     MuxChardev *d = MUX_CHARDEV(chr);
202     int m = d->focus;
203     CharBackend *be = d->backends[m];
204 
205     while (be && d->prod[m] != d->cons[m] &&
206            be->chr_can_read && be->chr_can_read(be->opaque)) {
207         be->chr_read(be->opaque,
208                      &d->buffer[m][d->cons[m]++ & MUX_BUFFER_MASK], 1);
209     }
210 }
211 
212 static int mux_chr_can_read(void *opaque)
213 {
214     MuxChardev *d = MUX_CHARDEV(opaque);
215     int m = d->focus;
216     CharBackend *be = d->backends[m];
217 
218     if ((d->prod[m] - d->cons[m]) < MUX_BUFFER_SIZE) {
219         return 1;
220     }
221 
222     if (be && be->chr_can_read) {
223         return be->chr_can_read(be->opaque);
224     }
225 
226     return 0;
227 }
228 
229 static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
230 {
231     Chardev *chr = CHARDEV(opaque);
232     MuxChardev *d = MUX_CHARDEV(opaque);
233     int m = d->focus;
234     CharBackend *be = d->backends[m];
235     int i;
236 
237     mux_chr_accept_input(opaque);
238 
239     for (i = 0; i < size; i++)
240         if (mux_proc_byte(chr, d, buf[i])) {
241             if (d->prod[m] == d->cons[m] &&
242                 be && be->chr_can_read &&
243                 be->chr_can_read(be->opaque)) {
244                 be->chr_read(be->opaque, &buf[i], 1);
245             } else {
246                 d->buffer[m][d->prod[m]++ & MUX_BUFFER_MASK] = buf[i];
247             }
248         }
249 }
250 
251 void mux_chr_send_all_event(Chardev *chr, QEMUChrEvent event)
252 {
253     MuxChardev *d = MUX_CHARDEV(chr);
254     int bit;
255 
256     if (!muxes_opened) {
257         return;
258     }
259 
260     /* Send the event to all registered listeners */
261     bit = -1;
262     while ((bit = find_next_bit(&d->mux_bitset, MAX_MUX, bit + 1)) < MAX_MUX) {
263         mux_chr_send_event(d, bit, event);
264     }
265 }
266 
267 static void mux_chr_event(void *opaque, QEMUChrEvent event)
268 {
269     mux_chr_send_all_event(CHARDEV(opaque), event);
270 }
271 
272 static GSource *mux_chr_add_watch(Chardev *s, GIOCondition cond)
273 {
274     MuxChardev *d = MUX_CHARDEV(s);
275     Chardev *chr = qemu_chr_fe_get_driver(&d->chr);
276     ChardevClass *cc = CHARDEV_GET_CLASS(chr);
277 
278     if (!cc->chr_add_watch) {
279         return NULL;
280     }
281 
282     return cc->chr_add_watch(chr, cond);
283 }
284 
285 static void char_mux_finalize(Object *obj)
286 {
287     MuxChardev *d = MUX_CHARDEV(obj);
288     int bit;
289 
290     bit = -1;
291     while ((bit = find_next_bit(&d->mux_bitset, MAX_MUX, bit + 1)) < MAX_MUX) {
292         CharBackend *be = d->backends[bit];
293         be->chr = NULL;
294         d->backends[bit] = NULL;
295     }
296     d->mux_bitset = 0;
297     qemu_chr_fe_deinit(&d->chr, false);
298 }
299 
300 static void mux_chr_update_read_handlers(Chardev *chr)
301 {
302     MuxChardev *d = MUX_CHARDEV(chr);
303 
304     /* Fix up the real driver with mux routines */
305     qemu_chr_fe_set_handlers_full(&d->chr,
306                                   mux_chr_can_read,
307                                   mux_chr_read,
308                                   mux_chr_event,
309                                   NULL,
310                                   chr,
311                                   chr->gcontext, true, false);
312 }
313 
314 bool mux_chr_attach_frontend(MuxChardev *d, CharBackend *b,
315                              unsigned int *tag, Error **errp)
316 {
317     unsigned int bit;
318 
319     bit = find_next_zero_bit(&d->mux_bitset, MAX_MUX, 0);
320     if (bit >= MAX_MUX) {
321         error_setg(errp,
322                    "too many uses of multiplexed chardev '%s'"
323                    " (maximum is " stringify(MAX_MUX) ")",
324                    d->parent.label);
325         return false;
326     }
327 
328     d->mux_bitset |= (1 << bit);
329     d->backends[bit] = b;
330     *tag = bit;
331 
332     return true;
333 }
334 
335 bool mux_chr_detach_frontend(MuxChardev *d, unsigned int tag)
336 {
337     unsigned int bit;
338 
339     bit = find_next_bit(&d->mux_bitset, MAX_MUX, tag);
340     if (bit != tag) {
341         return false;
342     }
343 
344     d->mux_bitset &= ~(1 << bit);
345     d->backends[bit] = NULL;
346 
347     return true;
348 }
349 
350 void mux_set_focus(Chardev *chr, unsigned int focus)
351 {
352     MuxChardev *d = MUX_CHARDEV(chr);
353 
354     assert(find_next_bit(&d->mux_bitset, MAX_MUX, focus) == focus);
355 
356     if (d->focus != -1) {
357         mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT);
358     }
359 
360     d->focus = focus;
361     chr->be = d->backends[focus];
362     mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN);
363 }
364 
365 static void qemu_chr_open_mux(Chardev *chr,
366                               ChardevBackend *backend,
367                               bool *be_opened,
368                               Error **errp)
369 {
370     ChardevMux *mux = backend->u.mux.data;
371     Chardev *drv;
372     MuxChardev *d = MUX_CHARDEV(chr);
373 
374     drv = qemu_chr_find(mux->chardev);
375     if (drv == NULL) {
376         error_setg(errp, "mux: base chardev %s not found", mux->chardev);
377         return;
378     }
379 
380     d->focus = -1;
381     /* only default to opened state if we've realized the initial
382      * set of muxes
383      */
384     *be_opened = muxes_opened;
385     qemu_chr_fe_init(&d->chr, drv, errp);
386 }
387 
388 static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend,
389                                Error **errp)
390 {
391     const char *chardev = qemu_opt_get(opts, "chardev");
392     ChardevMux *mux;
393 
394     if (chardev == NULL) {
395         error_setg(errp, "chardev: mux: no chardev given");
396         return;
397     }
398     backend->type = CHARDEV_BACKEND_KIND_MUX;
399     mux = backend->u.mux.data = g_new0(ChardevMux, 1);
400     qemu_chr_parse_common(opts, qapi_ChardevMux_base(mux));
401     mux->chardev = g_strdup(chardev);
402 }
403 
404 /**
405  * Called after processing of default and command-line-specified
406  * chardevs to deliver CHR_EVENT_OPENED events to any FEs attached
407  * to a mux chardev. This is done here to ensure that
408  * output/prompts/banners are only displayed for the FE that has
409  * focus when initial command-line processing/machine init is
410  * completed.
411  *
412  * After this point, any new FE attached to any new or existing
413  * mux will receive CHR_EVENT_OPENED notifications for the BE
414  * immediately.
415  */
416 static void open_muxes(Chardev *chr)
417 {
418     /* send OPENED to all already-attached FEs */
419     mux_chr_send_all_event(chr, CHR_EVENT_OPENED);
420 
421     /*
422      * mark mux as OPENED so any new FEs will immediately receive
423      * OPENED event
424      */
425     chr->be_open = 1;
426 }
427 
428 void suspend_mux_open(void)
429 {
430     muxes_opened = false;
431 }
432 
433 static int chardev_options_parsed_cb(Object *child, void *opaque)
434 {
435     Chardev *chr = (Chardev *)child;
436 
437     if (!chr->be_open && CHARDEV_IS_MUX(chr)) {
438         open_muxes(chr);
439     }
440 
441     return 0;
442 }
443 
444 void resume_mux_open(void)
445 {
446     muxes_opened = true;
447     object_child_foreach(get_chardevs_root(),
448                          chardev_options_parsed_cb, NULL);
449 }
450 
451 static void char_mux_class_init(ObjectClass *oc, void *data)
452 {
453     ChardevClass *cc = CHARDEV_CLASS(oc);
454 
455     cc->parse = qemu_chr_parse_mux;
456     cc->open = qemu_chr_open_mux;
457     cc->chr_write = mux_chr_write;
458     cc->chr_accept_input = mux_chr_accept_input;
459     cc->chr_add_watch = mux_chr_add_watch;
460     cc->chr_be_event = mux_chr_be_event;
461     cc->chr_update_read_handler = mux_chr_update_read_handlers;
462 }
463 
464 static const TypeInfo char_mux_type_info = {
465     .name = TYPE_CHARDEV_MUX,
466     .parent = TYPE_CHARDEV,
467     .class_init = char_mux_class_init,
468     .instance_size = sizeof(MuxChardev),
469     .instance_finalize = char_mux_finalize,
470 };
471 
472 static void register_types(void)
473 {
474     type_register_static(&char_mux_type_info);
475 }
476 
477 type_init(register_types);
478