char-mux.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  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. #include "qemu/osdep.h"
  25. #include "qapi/error.h"
  26. #include "qemu/module.h"
  27. #include "qemu/option.h"
  28. #include "chardev/char.h"
  29. #include "sysemu/block-backend.h"
  30. #include "qapi/qapi-commands-control.h"
  31. #include "chardev-internal.h"
  32. /* MUX driver for serial I/O splitting */
  33. /*
  34. * Set to false by suspend_mux_open. Open events are delayed until
  35. * resume_mux_open. Usually suspend_mux_open is called before
  36. * command line processing and resume_mux_open afterwards.
  37. */
  38. static bool muxes_opened = true;
  39. /* Called with chr_write_lock held. */
  40. static int mux_chr_write(Chardev *chr, const uint8_t *buf, int len)
  41. {
  42. MuxChardev *d = MUX_CHARDEV(chr);
  43. int ret;
  44. if (!d->timestamps) {
  45. ret = qemu_chr_fe_write(&d->chr, buf, len);
  46. } else {
  47. int i;
  48. ret = 0;
  49. for (i = 0; i < len; i++) {
  50. if (d->linestart) {
  51. char buf1[64];
  52. int64_t ti;
  53. int secs;
  54. ti = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
  55. if (d->timestamps_start == -1) {
  56. d->timestamps_start = ti;
  57. }
  58. ti -= d->timestamps_start;
  59. secs = ti / 1000;
  60. snprintf(buf1, sizeof(buf1),
  61. "[%02d:%02d:%02d.%03d] ",
  62. secs / 3600,
  63. (secs / 60) % 60,
  64. secs % 60,
  65. (int)(ti % 1000));
  66. /* XXX this blocks entire thread. Rewrite to use
  67. * qemu_chr_fe_write and background I/O callbacks */
  68. qemu_chr_fe_write_all(&d->chr,
  69. (uint8_t *)buf1, strlen(buf1));
  70. d->linestart = 0;
  71. }
  72. ret += qemu_chr_fe_write(&d->chr, buf + i, 1);
  73. if (buf[i] == '\n') {
  74. d->linestart = 1;
  75. }
  76. }
  77. }
  78. return ret;
  79. }
  80. static const char * const mux_help[] = {
  81. "% h print this help\n\r",
  82. "% x exit emulator\n\r",
  83. "% s save disk data back to file (if -snapshot)\n\r",
  84. "% t toggle console timestamps\n\r",
  85. "% b send break (magic sysrq)\n\r",
  86. "% c switch between console and monitor\n\r",
  87. "% % sends %\n\r",
  88. NULL
  89. };
  90. int term_escape_char = 0x01; /* ctrl-a is used for escape */
  91. static void mux_print_help(Chardev *chr)
  92. {
  93. int i, j;
  94. char ebuf[15] = "Escape-Char";
  95. char cbuf[50] = "\n\r";
  96. if (term_escape_char > 0 && term_escape_char < 26) {
  97. snprintf(cbuf, sizeof(cbuf), "\n\r");
  98. snprintf(ebuf, sizeof(ebuf), "C-%c", term_escape_char - 1 + 'a');
  99. } else {
  100. snprintf(cbuf, sizeof(cbuf),
  101. "\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r",
  102. term_escape_char);
  103. }
  104. /* XXX this blocks entire thread. Rewrite to use
  105. * qemu_chr_fe_write and background I/O callbacks */
  106. qemu_chr_write_all(chr, (uint8_t *)cbuf, strlen(cbuf));
  107. for (i = 0; mux_help[i] != NULL; i++) {
  108. for (j = 0; mux_help[i][j] != '\0'; j++) {
  109. if (mux_help[i][j] == '%') {
  110. qemu_chr_write_all(chr, (uint8_t *)ebuf, strlen(ebuf));
  111. } else {
  112. qemu_chr_write_all(chr, (uint8_t *)&mux_help[i][j], 1);
  113. }
  114. }
  115. }
  116. }
  117. static void mux_chr_send_event(MuxChardev *d, int mux_nr, QEMUChrEvent event)
  118. {
  119. CharBackend *be = d->backends[mux_nr];
  120. if (be && be->chr_event) {
  121. be->chr_event(be->opaque, event);
  122. }
  123. }
  124. static void mux_chr_be_event(Chardev *chr, QEMUChrEvent event)
  125. {
  126. MuxChardev *d = MUX_CHARDEV(chr);
  127. if (d->focus != -1) {
  128. mux_chr_send_event(d, d->focus, event);
  129. }
  130. }
  131. static int mux_proc_byte(Chardev *chr, MuxChardev *d, int ch)
  132. {
  133. if (d->term_got_escape) {
  134. d->term_got_escape = 0;
  135. if (ch == term_escape_char) {
  136. goto send_char;
  137. }
  138. switch (ch) {
  139. case '?':
  140. case 'h':
  141. mux_print_help(chr);
  142. break;
  143. case 'x':
  144. {
  145. const char *term = "QEMU: Terminated\n\r";
  146. qemu_chr_write_all(chr, (uint8_t *)term, strlen(term));
  147. qmp_quit(NULL);
  148. break;
  149. }
  150. case 's':
  151. blk_commit_all();
  152. break;
  153. case 'b':
  154. qemu_chr_be_event(chr, CHR_EVENT_BREAK);
  155. break;
  156. case 'c':
  157. assert(d->mux_cnt > 0); /* handler registered with first fe */
  158. /* Switch to the next registered device */
  159. mux_set_focus(chr, (d->focus + 1) % d->mux_cnt);
  160. break;
  161. case 't':
  162. d->timestamps = !d->timestamps;
  163. d->timestamps_start = -1;
  164. d->linestart = 0;
  165. break;
  166. }
  167. } else if (ch == term_escape_char) {
  168. d->term_got_escape = 1;
  169. } else {
  170. send_char:
  171. return 1;
  172. }
  173. return 0;
  174. }
  175. static void mux_chr_accept_input(Chardev *chr)
  176. {
  177. MuxChardev *d = MUX_CHARDEV(chr);
  178. int m = d->focus;
  179. CharBackend *be = d->backends[m];
  180. while (be && d->prod[m] != d->cons[m] &&
  181. be->chr_can_read && be->chr_can_read(be->opaque)) {
  182. be->chr_read(be->opaque,
  183. &d->buffer[m][d->cons[m]++ & MUX_BUFFER_MASK], 1);
  184. }
  185. }
  186. static int mux_chr_can_read(void *opaque)
  187. {
  188. MuxChardev *d = MUX_CHARDEV(opaque);
  189. int m = d->focus;
  190. CharBackend *be = d->backends[m];
  191. if ((d->prod[m] - d->cons[m]) < MUX_BUFFER_SIZE) {
  192. return 1;
  193. }
  194. if (be && be->chr_can_read) {
  195. return be->chr_can_read(be->opaque);
  196. }
  197. return 0;
  198. }
  199. static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
  200. {
  201. Chardev *chr = CHARDEV(opaque);
  202. MuxChardev *d = MUX_CHARDEV(opaque);
  203. int m = d->focus;
  204. CharBackend *be = d->backends[m];
  205. int i;
  206. mux_chr_accept_input(opaque);
  207. for (i = 0; i < size; i++)
  208. if (mux_proc_byte(chr, d, buf[i])) {
  209. if (d->prod[m] == d->cons[m] &&
  210. be && be->chr_can_read &&
  211. be->chr_can_read(be->opaque)) {
  212. be->chr_read(be->opaque, &buf[i], 1);
  213. } else {
  214. d->buffer[m][d->prod[m]++ & MUX_BUFFER_MASK] = buf[i];
  215. }
  216. }
  217. }
  218. void mux_chr_send_all_event(Chardev *chr, QEMUChrEvent event)
  219. {
  220. MuxChardev *d = MUX_CHARDEV(chr);
  221. int i;
  222. if (!muxes_opened) {
  223. return;
  224. }
  225. /* Send the event to all registered listeners */
  226. for (i = 0; i < d->mux_cnt; i++) {
  227. mux_chr_send_event(d, i, event);
  228. }
  229. }
  230. static void mux_chr_event(void *opaque, QEMUChrEvent event)
  231. {
  232. mux_chr_send_all_event(CHARDEV(opaque), event);
  233. }
  234. static GSource *mux_chr_add_watch(Chardev *s, GIOCondition cond)
  235. {
  236. MuxChardev *d = MUX_CHARDEV(s);
  237. Chardev *chr = qemu_chr_fe_get_driver(&d->chr);
  238. ChardevClass *cc = CHARDEV_GET_CLASS(chr);
  239. if (!cc->chr_add_watch) {
  240. return NULL;
  241. }
  242. return cc->chr_add_watch(chr, cond);
  243. }
  244. static void char_mux_finalize(Object *obj)
  245. {
  246. MuxChardev *d = MUX_CHARDEV(obj);
  247. int i;
  248. for (i = 0; i < d->mux_cnt; i++) {
  249. CharBackend *be = d->backends[i];
  250. if (be) {
  251. be->chr = NULL;
  252. }
  253. }
  254. qemu_chr_fe_deinit(&d->chr, false);
  255. }
  256. static void mux_chr_update_read_handlers(Chardev *chr)
  257. {
  258. MuxChardev *d = MUX_CHARDEV(chr);
  259. /* Fix up the real driver with mux routines */
  260. qemu_chr_fe_set_handlers_full(&d->chr,
  261. mux_chr_can_read,
  262. mux_chr_read,
  263. mux_chr_event,
  264. NULL,
  265. chr,
  266. chr->gcontext, true, false);
  267. }
  268. void mux_set_focus(Chardev *chr, int focus)
  269. {
  270. MuxChardev *d = MUX_CHARDEV(chr);
  271. assert(focus >= 0);
  272. assert(focus < d->mux_cnt);
  273. if (d->focus != -1) {
  274. mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT);
  275. }
  276. d->focus = focus;
  277. chr->be = d->backends[focus];
  278. mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN);
  279. }
  280. static void qemu_chr_open_mux(Chardev *chr,
  281. ChardevBackend *backend,
  282. bool *be_opened,
  283. Error **errp)
  284. {
  285. ChardevMux *mux = backend->u.mux.data;
  286. Chardev *drv;
  287. MuxChardev *d = MUX_CHARDEV(chr);
  288. drv = qemu_chr_find(mux->chardev);
  289. if (drv == NULL) {
  290. error_setg(errp, "mux: base chardev %s not found", mux->chardev);
  291. return;
  292. }
  293. d->focus = -1;
  294. /* only default to opened state if we've realized the initial
  295. * set of muxes
  296. */
  297. *be_opened = muxes_opened;
  298. qemu_chr_fe_init(&d->chr, drv, errp);
  299. }
  300. static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend,
  301. Error **errp)
  302. {
  303. const char *chardev = qemu_opt_get(opts, "chardev");
  304. ChardevMux *mux;
  305. if (chardev == NULL) {
  306. error_setg(errp, "chardev: mux: no chardev given");
  307. return;
  308. }
  309. backend->type = CHARDEV_BACKEND_KIND_MUX;
  310. mux = backend->u.mux.data = g_new0(ChardevMux, 1);
  311. qemu_chr_parse_common(opts, qapi_ChardevMux_base(mux));
  312. mux->chardev = g_strdup(chardev);
  313. }
  314. /**
  315. * Called after processing of default and command-line-specified
  316. * chardevs to deliver CHR_EVENT_OPENED events to any FEs attached
  317. * to a mux chardev. This is done here to ensure that
  318. * output/prompts/banners are only displayed for the FE that has
  319. * focus when initial command-line processing/machine init is
  320. * completed.
  321. *
  322. * After this point, any new FE attached to any new or existing
  323. * mux will receive CHR_EVENT_OPENED notifications for the BE
  324. * immediately.
  325. */
  326. static void open_muxes(Chardev *chr)
  327. {
  328. /* send OPENED to all already-attached FEs */
  329. mux_chr_send_all_event(chr, CHR_EVENT_OPENED);
  330. /*
  331. * mark mux as OPENED so any new FEs will immediately receive
  332. * OPENED event
  333. */
  334. chr->be_open = 1;
  335. }
  336. void suspend_mux_open(void)
  337. {
  338. muxes_opened = false;
  339. }
  340. static int chardev_options_parsed_cb(Object *child, void *opaque)
  341. {
  342. Chardev *chr = (Chardev *)child;
  343. if (!chr->be_open && CHARDEV_IS_MUX(chr)) {
  344. open_muxes(chr);
  345. }
  346. return 0;
  347. }
  348. void resume_mux_open(void)
  349. {
  350. muxes_opened = true;
  351. object_child_foreach(get_chardevs_root(),
  352. chardev_options_parsed_cb, NULL);
  353. }
  354. static void char_mux_class_init(ObjectClass *oc, void *data)
  355. {
  356. ChardevClass *cc = CHARDEV_CLASS(oc);
  357. cc->parse = qemu_chr_parse_mux;
  358. cc->open = qemu_chr_open_mux;
  359. cc->chr_write = mux_chr_write;
  360. cc->chr_accept_input = mux_chr_accept_input;
  361. cc->chr_add_watch = mux_chr_add_watch;
  362. cc->chr_be_event = mux_chr_be_event;
  363. cc->chr_update_read_handler = mux_chr_update_read_handlers;
  364. }
  365. static const TypeInfo char_mux_type_info = {
  366. .name = TYPE_CHARDEV_MUX,
  367. .parent = TYPE_CHARDEV,
  368. .class_init = char_mux_class_init,
  369. .instance_size = sizeof(MuxChardev),
  370. .instance_finalize = char_mux_finalize,
  371. };
  372. static void register_types(void)
  373. {
  374. type_register_static(&char_mux_type_info);
  375. }
  376. type_init(register_types);