4 * Copyright (c) 2003-2008 Fabrice Bellard
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
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"
35 /* MUX driver for serial I/O splitting */
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.
42 static bool muxes_opened
= true;
44 /* Called with chr_write_lock held. */
45 static int mux_chr_write(Chardev
*chr
, const uint8_t *buf
, int len
)
47 MuxChardev
*d
= MUX_CHARDEV(chr
);
50 ret
= qemu_chr_fe_write(&d
->chr
, buf
, len
);
55 for (i
= 0; i
< len
; i
++) {
61 ti
= qemu_clock_get_ms(QEMU_CLOCK_REALTIME
);
62 if (d
->timestamps_start
== -1) {
63 d
->timestamps_start
= ti
;
65 ti
-= d
->timestamps_start
;
67 snprintf(buf1
, sizeof(buf1
),
68 "[%02d:%02d:%02d.%03d] ",
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
));
79 ret
+= qemu_chr_fe_write(&d
->chr
, buf
+ i
, 1);
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",
99 int term_escape_char
= 0x01; /* ctrl-a is used for escape */
100 static void mux_print_help(Chardev
*chr
)
103 char ebuf
[15] = "Escape-Char";
104 char cbuf
[50] = "\n\r";
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');
110 snprintf(cbuf
, sizeof(cbuf
),
111 "\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r",
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
));
122 qemu_chr_write_all(chr
, (uint8_t *)&mux_help
[i
][j
], 1);
128 static void mux_chr_send_event(MuxChardev
*d
, unsigned int mux_nr
,
131 CharBackend
*be
= d
->backends
[mux_nr
];
133 if (be
&& be
->chr_event
) {
134 be
->chr_event(be
->opaque
, event
);
138 static void mux_chr_be_event(Chardev
*chr
, QEMUChrEvent event
)
140 MuxChardev
*d
= MUX_CHARDEV(chr
);
142 if (d
->focus
!= -1) {
143 mux_chr_send_event(d
, d
->focus
, event
);
147 static int mux_proc_byte(Chardev
*chr
, MuxChardev
*d
, int ch
)
149 if (d
->term_got_escape
) {
150 d
->term_got_escape
= false;
151 if (ch
== term_escape_char
) {
161 const char *term
= "QEMU: Terminated\n\r";
162 qemu_chr_write_all(chr
, (uint8_t *)term
, strlen(term
));
170 qemu_chr_be_event(chr
, CHR_EVENT_BREAK
);
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);
182 mux_set_focus(chr
, bit
);
185 d
->timestamps
= !d
->timestamps
;
186 d
->timestamps_start
= -1;
187 d
->linestart
= false;
190 } else if (ch
== term_escape_char
) {
191 d
->term_got_escape
= true;
199 static void mux_chr_accept_input(Chardev
*chr
)
201 MuxChardev
*d
= MUX_CHARDEV(chr
);
203 CharBackend
*be
= d
->backends
[m
];
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);
212 static int mux_chr_can_read(void *opaque
)
214 MuxChardev
*d
= MUX_CHARDEV(opaque
);
216 CharBackend
*be
= d
->backends
[m
];
218 if ((d
->prod
[m
] - d
->cons
[m
]) < MUX_BUFFER_SIZE
) {
222 if (be
&& be
->chr_can_read
) {
223 return be
->chr_can_read(be
->opaque
);
229 static void mux_chr_read(void *opaque
, const uint8_t *buf
, int size
)
231 Chardev
*chr
= CHARDEV(opaque
);
232 MuxChardev
*d
= MUX_CHARDEV(opaque
);
234 CharBackend
*be
= d
->backends
[m
];
237 mux_chr_accept_input(opaque
);
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);
246 d
->buffer
[m
][d
->prod
[m
]++ & MUX_BUFFER_MASK
] = buf
[i
];
251 void mux_chr_send_all_event(Chardev
*chr
, QEMUChrEvent event
)
253 MuxChardev
*d
= MUX_CHARDEV(chr
);
260 /* Send the event to all registered listeners */
262 while ((bit
= find_next_bit(&d
->mux_bitset
, MAX_MUX
, bit
+ 1)) < MAX_MUX
) {
263 mux_chr_send_event(d
, bit
, event
);
267 static void mux_chr_event(void *opaque
, QEMUChrEvent event
)
269 mux_chr_send_all_event(CHARDEV(opaque
), event
);
272 static GSource
*mux_chr_add_watch(Chardev
*s
, GIOCondition cond
)
274 MuxChardev
*d
= MUX_CHARDEV(s
);
275 Chardev
*chr
= qemu_chr_fe_get_driver(&d
->chr
);
276 ChardevClass
*cc
= CHARDEV_GET_CLASS(chr
);
278 if (!cc
->chr_add_watch
) {
282 return cc
->chr_add_watch(chr
, cond
);
285 static void char_mux_finalize(Object
*obj
)
287 MuxChardev
*d
= MUX_CHARDEV(obj
);
291 while ((bit
= find_next_bit(&d
->mux_bitset
, MAX_MUX
, bit
+ 1)) < MAX_MUX
) {
292 CharBackend
*be
= d
->backends
[bit
];
294 d
->backends
[bit
] = NULL
;
297 qemu_chr_fe_deinit(&d
->chr
, false);
300 static void mux_chr_update_read_handlers(Chardev
*chr
)
302 MuxChardev
*d
= MUX_CHARDEV(chr
);
304 /* Fix up the real driver with mux routines */
305 qemu_chr_fe_set_handlers_full(&d
->chr
,
311 chr
->gcontext
, true, false);
314 bool mux_chr_attach_frontend(MuxChardev
*d
, CharBackend
*b
,
315 unsigned int *tag
, Error
**errp
)
319 bit
= find_next_zero_bit(&d
->mux_bitset
, MAX_MUX
, 0);
320 if (bit
>= MAX_MUX
) {
322 "too many uses of multiplexed chardev '%s'"
323 " (maximum is " stringify(MAX_MUX
) ")",
328 d
->mux_bitset
|= (1 << bit
);
329 d
->backends
[bit
] = b
;
335 bool mux_chr_detach_frontend(MuxChardev
*d
, unsigned int tag
)
339 bit
= find_next_bit(&d
->mux_bitset
, MAX_MUX
, tag
);
344 d
->mux_bitset
&= ~(1 << bit
);
345 d
->backends
[bit
] = NULL
;
350 void mux_set_focus(Chardev
*chr
, unsigned int focus
)
352 MuxChardev
*d
= MUX_CHARDEV(chr
);
354 assert(find_next_bit(&d
->mux_bitset
, MAX_MUX
, focus
) == focus
);
356 if (d
->focus
!= -1) {
357 mux_chr_send_event(d
, d
->focus
, CHR_EVENT_MUX_OUT
);
361 chr
->be
= d
->backends
[focus
];
362 mux_chr_send_event(d
, d
->focus
, CHR_EVENT_MUX_IN
);
365 static void qemu_chr_open_mux(Chardev
*chr
,
366 ChardevBackend
*backend
,
370 ChardevMux
*mux
= backend
->u
.mux
.data
;
372 MuxChardev
*d
= MUX_CHARDEV(chr
);
374 drv
= qemu_chr_find(mux
->chardev
);
376 error_setg(errp
, "mux: base chardev %s not found", mux
->chardev
);
381 /* only default to opened state if we've realized the initial
384 *be_opened
= muxes_opened
;
385 qemu_chr_fe_init(&d
->chr
, drv
, errp
);
388 static void qemu_chr_parse_mux(QemuOpts
*opts
, ChardevBackend
*backend
,
391 const char *chardev
= qemu_opt_get(opts
, "chardev");
394 if (chardev
== NULL
) {
395 error_setg(errp
, "chardev: mux: no chardev given");
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
);
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
412 * After this point, any new FE attached to any new or existing
413 * mux will receive CHR_EVENT_OPENED notifications for the BE
416 static void open_muxes(Chardev
*chr
)
418 /* send OPENED to all already-attached FEs */
419 mux_chr_send_all_event(chr
, CHR_EVENT_OPENED
);
422 * mark mux as OPENED so any new FEs will immediately receive
428 void suspend_mux_open(void)
430 muxes_opened
= false;
433 static int chardev_options_parsed_cb(Object
*child
, void *opaque
)
435 Chardev
*chr
= (Chardev
*)child
;
437 if (!chr
->be_open
&& CHARDEV_IS_MUX(chr
)) {
444 void resume_mux_open(void)
447 object_child_foreach(get_chardevs_root(),
448 chardev_options_parsed_cb
, NULL
);
451 static void char_mux_class_init(ObjectClass
*oc
, void *data
)
453 ChardevClass
*cc
= CHARDEV_CLASS(oc
);
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
;
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
,
472 static void register_types(void)
474 type_register_static(&char_mux_type_info
);
477 type_init(register_types
);