xref: /openbmc/qemu/ui/console.c (revision a00e37a4)
1 /*
2  * QEMU graphical console
3  *
4  * Copyright (c) 2004 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 "ui/console.h"
27 #include "hw/qdev-core.h"
28 #include "qapi/error.h"
29 #include "qapi/qapi-commands-ui.h"
30 #include "qemu/fifo8.h"
31 #include "qemu/main-loop.h"
32 #include "qemu/module.h"
33 #include "qemu/option.h"
34 #include "qemu/timer.h"
35 #include "chardev/char.h"
36 #include "trace.h"
37 #include "exec/memory.h"
38 #include "io/channel-file.h"
39 #include "qom/object.h"
40 
41 #define DEFAULT_BACKSCROLL 512
42 #define CONSOLE_CURSOR_PERIOD 500
43 
44 typedef struct TextAttributes {
45     uint8_t fgcol:4;
46     uint8_t bgcol:4;
47     uint8_t bold:1;
48     uint8_t uline:1;
49     uint8_t blink:1;
50     uint8_t invers:1;
51     uint8_t unvisible:1;
52 } TextAttributes;
53 
54 typedef struct TextCell {
55     uint8_t ch;
56     TextAttributes t_attrib;
57 } TextCell;
58 
59 #define MAX_ESC_PARAMS 3
60 
61 enum TTYState {
62     TTY_STATE_NORM,
63     TTY_STATE_ESC,
64     TTY_STATE_CSI,
65 };
66 
67 typedef enum {
68     GRAPHIC_CONSOLE,
69     TEXT_CONSOLE,
70     TEXT_CONSOLE_FIXED_SIZE
71 } console_type_t;
72 
73 struct QemuConsole {
74     Object parent;
75 
76     int index;
77     console_type_t console_type;
78     DisplayState *ds;
79     DisplaySurface *surface;
80     int dcls;
81     DisplayChangeListener *gl;
82     bool gl_block;
83     int window_id;
84 
85     /* Graphic console state.  */
86     Object *device;
87     uint32_t head;
88     QemuUIInfo ui_info;
89     QEMUTimer *ui_timer;
90     const GraphicHwOps *hw_ops;
91     void *hw;
92 
93     /* Text console state */
94     int width;
95     int height;
96     int total_height;
97     int backscroll_height;
98     int x, y;
99     int x_saved, y_saved;
100     int y_displayed;
101     int y_base;
102     TextAttributes t_attrib_default; /* default text attributes */
103     TextAttributes t_attrib; /* currently active text attributes */
104     TextCell *cells;
105     int text_x[2], text_y[2], cursor_invalidate;
106     int echo;
107 
108     int update_x0;
109     int update_y0;
110     int update_x1;
111     int update_y1;
112 
113     enum TTYState state;
114     int esc_params[MAX_ESC_PARAMS];
115     int nb_esc_params;
116 
117     Chardev *chr;
118     /* fifo for key pressed */
119     Fifo8 out_fifo;
120     CoQueue dump_queue;
121 
122     QTAILQ_ENTRY(QemuConsole) next;
123 };
124 
125 struct DisplayState {
126     QEMUTimer *gui_timer;
127     uint64_t last_update;
128     uint64_t update_interval;
129     bool refreshing;
130     bool have_gfx;
131     bool have_text;
132 
133     QLIST_HEAD(, DisplayChangeListener) listeners;
134 };
135 
136 static DisplayState *display_state;
137 static QemuConsole *active_console;
138 static QTAILQ_HEAD(, QemuConsole) consoles =
139     QTAILQ_HEAD_INITIALIZER(consoles);
140 static bool cursor_visible_phase;
141 static QEMUTimer *cursor_timer;
142 
143 static void text_console_do_init(Chardev *chr, DisplayState *ds);
144 static void dpy_refresh(DisplayState *s);
145 static DisplayState *get_alloc_displaystate(void);
146 static void text_console_update_cursor_timer(void);
147 static void text_console_update_cursor(void *opaque);
148 
149 static void gui_update(void *opaque)
150 {
151     uint64_t interval = GUI_REFRESH_INTERVAL_IDLE;
152     uint64_t dcl_interval;
153     DisplayState *ds = opaque;
154     DisplayChangeListener *dcl;
155     QemuConsole *con;
156 
157     ds->refreshing = true;
158     dpy_refresh(ds);
159     ds->refreshing = false;
160 
161     QLIST_FOREACH(dcl, &ds->listeners, next) {
162         dcl_interval = dcl->update_interval ?
163             dcl->update_interval : GUI_REFRESH_INTERVAL_DEFAULT;
164         if (interval > dcl_interval) {
165             interval = dcl_interval;
166         }
167     }
168     if (ds->update_interval != interval) {
169         ds->update_interval = interval;
170         QTAILQ_FOREACH(con, &consoles, next) {
171             if (con->hw_ops->update_interval) {
172                 con->hw_ops->update_interval(con->hw, interval);
173             }
174         }
175         trace_console_refresh(interval);
176     }
177     ds->last_update = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
178     timer_mod(ds->gui_timer, ds->last_update + interval);
179 }
180 
181 static void gui_setup_refresh(DisplayState *ds)
182 {
183     DisplayChangeListener *dcl;
184     bool need_timer = false;
185     bool have_gfx = false;
186     bool have_text = false;
187 
188     QLIST_FOREACH(dcl, &ds->listeners, next) {
189         if (dcl->ops->dpy_refresh != NULL) {
190             need_timer = true;
191         }
192         if (dcl->ops->dpy_gfx_update != NULL) {
193             have_gfx = true;
194         }
195         if (dcl->ops->dpy_text_update != NULL) {
196             have_text = true;
197         }
198     }
199 
200     if (need_timer && ds->gui_timer == NULL) {
201         ds->gui_timer = timer_new_ms(QEMU_CLOCK_REALTIME, gui_update, ds);
202         timer_mod(ds->gui_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
203     }
204     if (!need_timer && ds->gui_timer != NULL) {
205         timer_free(ds->gui_timer);
206         ds->gui_timer = NULL;
207     }
208 
209     ds->have_gfx = have_gfx;
210     ds->have_text = have_text;
211 }
212 
213 void graphic_hw_update_done(QemuConsole *con)
214 {
215     if (con) {
216         qemu_co_queue_restart_all(&con->dump_queue);
217     }
218 }
219 
220 void graphic_hw_update(QemuConsole *con)
221 {
222     bool async = false;
223     con = con ? con : active_console;
224     if (!con) {
225         return;
226     }
227     if (con->hw_ops->gfx_update) {
228         con->hw_ops->gfx_update(con->hw);
229         async = con->hw_ops->gfx_update_async;
230     }
231     if (!async) {
232         graphic_hw_update_done(con);
233     }
234 }
235 
236 void graphic_hw_gl_block(QemuConsole *con, bool block)
237 {
238     assert(con != NULL);
239 
240     con->gl_block = block;
241     if (con->hw_ops->gl_block) {
242         con->hw_ops->gl_block(con->hw, block);
243     }
244 }
245 
246 void graphic_hw_gl_flushed(QemuConsole *con)
247 {
248     assert(con != NULL);
249 
250     if (con->hw_ops->gl_flushed) {
251         con->hw_ops->gl_flushed(con->hw);
252     }
253 }
254 
255 int qemu_console_get_window_id(QemuConsole *con)
256 {
257     return con->window_id;
258 }
259 
260 void qemu_console_set_window_id(QemuConsole *con, int window_id)
261 {
262     con->window_id = window_id;
263 }
264 
265 void graphic_hw_invalidate(QemuConsole *con)
266 {
267     if (!con) {
268         con = active_console;
269     }
270     if (con && con->hw_ops->invalidate) {
271         con->hw_ops->invalidate(con->hw);
272     }
273 }
274 
275 static bool ppm_save(int fd, pixman_image_t *image, Error **errp)
276 {
277     int width = pixman_image_get_width(image);
278     int height = pixman_image_get_height(image);
279     g_autoptr(Object) ioc = OBJECT(qio_channel_file_new_fd(fd));
280     g_autofree char *header = NULL;
281     g_autoptr(pixman_image_t) linebuf = NULL;
282     int y;
283 
284     trace_ppm_save(fd, image);
285 
286     header = g_strdup_printf("P6\n%d %d\n%d\n", width, height, 255);
287     if (qio_channel_write_all(QIO_CHANNEL(ioc),
288                               header, strlen(header), errp) < 0) {
289         return false;
290     }
291 
292     linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width);
293     for (y = 0; y < height; y++) {
294         qemu_pixman_linebuf_fill(linebuf, image, width, 0, y);
295         if (qio_channel_write_all(QIO_CHANNEL(ioc),
296                                   (char *)pixman_image_get_data(linebuf),
297                                   pixman_image_get_stride(linebuf), errp) < 0) {
298             return false;
299         }
300     }
301 
302     return true;
303 }
304 
305 static void graphic_hw_update_bh(void *con)
306 {
307     graphic_hw_update(con);
308 }
309 
310 /* Safety: coroutine-only, concurrent-coroutine safe, main thread only */
311 void coroutine_fn
312 qmp_screendump(const char *filename, bool has_device, const char *device,
313                bool has_head, int64_t head, Error **errp)
314 {
315     g_autoptr(pixman_image_t) image = NULL;
316     QemuConsole *con;
317     DisplaySurface *surface;
318     int fd;
319 
320     if (has_device) {
321         con = qemu_console_lookup_by_device_name(device, has_head ? head : 0,
322                                                  errp);
323         if (!con) {
324             return;
325         }
326     } else {
327         if (has_head) {
328             error_setg(errp, "'head' must be specified together with 'device'");
329             return;
330         }
331         con = qemu_console_lookup_by_index(0);
332         if (!con) {
333             error_setg(errp, "There is no console to take a screendump from");
334             return;
335         }
336     }
337 
338     if (qemu_co_queue_empty(&con->dump_queue)) {
339         /* Defer the update, it will restart the pending coroutines */
340         aio_bh_schedule_oneshot(qemu_get_aio_context(),
341                                 graphic_hw_update_bh, con);
342     }
343     qemu_co_queue_wait(&con->dump_queue, NULL);
344 
345     /*
346      * All pending coroutines are woken up, while the BQL is held.  No
347      * further graphic update are possible until it is released.  Take
348      * an image ref before that.
349      */
350     surface = qemu_console_surface(con);
351     if (!surface) {
352         error_setg(errp, "no surface");
353         return;
354     }
355     image = pixman_image_ref(surface->image);
356 
357     fd = qemu_open_old(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
358     if (fd == -1) {
359         error_setg(errp, "failed to open file '%s': %s", filename,
360                    strerror(errno));
361         return;
362     }
363 
364     /*
365      * The image content could potentially be updated as the coroutine
366      * yields and releases the BQL. It could produce corrupted dump, but
367      * it should be otherwise safe.
368      */
369     if (!ppm_save(fd, image, errp)) {
370         qemu_unlink(filename);
371     }
372 }
373 
374 void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata)
375 {
376     if (!con) {
377         con = active_console;
378     }
379     if (con && con->hw_ops->text_update) {
380         con->hw_ops->text_update(con->hw, chardata);
381     }
382 }
383 
384 static void vga_fill_rect(QemuConsole *con,
385                           int posx, int posy, int width, int height,
386                           pixman_color_t color)
387 {
388     DisplaySurface *surface = qemu_console_surface(con);
389     pixman_rectangle16_t rect = {
390         .x = posx, .y = posy, .width = width, .height = height
391     };
392 
393     pixman_image_fill_rectangles(PIXMAN_OP_SRC, surface->image,
394                                  &color, 1, &rect);
395 }
396 
397 /* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
398 static void vga_bitblt(QemuConsole *con,
399                        int xs, int ys, int xd, int yd, int w, int h)
400 {
401     DisplaySurface *surface = qemu_console_surface(con);
402 
403     pixman_image_composite(PIXMAN_OP_SRC,
404                            surface->image, NULL, surface->image,
405                            xs, ys, 0, 0, xd, yd, w, h);
406 }
407 
408 /***********************************************************/
409 /* basic char display */
410 
411 #define FONT_HEIGHT 16
412 #define FONT_WIDTH 8
413 
414 #include "vgafont.h"
415 
416 #define QEMU_RGB(r, g, b)                                               \
417     { .red = r << 8, .green = g << 8, .blue = b << 8, .alpha = 0xffff }
418 
419 static const pixman_color_t color_table_rgb[2][8] = {
420     {   /* dark */
421         [QEMU_COLOR_BLACK]   = QEMU_RGB(0x00, 0x00, 0x00),  /* black */
422         [QEMU_COLOR_BLUE]    = QEMU_RGB(0x00, 0x00, 0xaa),  /* blue */
423         [QEMU_COLOR_GREEN]   = QEMU_RGB(0x00, 0xaa, 0x00),  /* green */
424         [QEMU_COLOR_CYAN]    = QEMU_RGB(0x00, 0xaa, 0xaa),  /* cyan */
425         [QEMU_COLOR_RED]     = QEMU_RGB(0xaa, 0x00, 0x00),  /* red */
426         [QEMU_COLOR_MAGENTA] = QEMU_RGB(0xaa, 0x00, 0xaa),  /* magenta */
427         [QEMU_COLOR_YELLOW]  = QEMU_RGB(0xaa, 0xaa, 0x00),  /* yellow */
428         [QEMU_COLOR_WHITE]   = QEMU_RGB(0xaa, 0xaa, 0xaa),  /* white */
429     },
430     {   /* bright */
431         [QEMU_COLOR_BLACK]   = QEMU_RGB(0x00, 0x00, 0x00),  /* black */
432         [QEMU_COLOR_BLUE]    = QEMU_RGB(0x00, 0x00, 0xff),  /* blue */
433         [QEMU_COLOR_GREEN]   = QEMU_RGB(0x00, 0xff, 0x00),  /* green */
434         [QEMU_COLOR_CYAN]    = QEMU_RGB(0x00, 0xff, 0xff),  /* cyan */
435         [QEMU_COLOR_RED]     = QEMU_RGB(0xff, 0x00, 0x00),  /* red */
436         [QEMU_COLOR_MAGENTA] = QEMU_RGB(0xff, 0x00, 0xff),  /* magenta */
437         [QEMU_COLOR_YELLOW]  = QEMU_RGB(0xff, 0xff, 0x00),  /* yellow */
438         [QEMU_COLOR_WHITE]   = QEMU_RGB(0xff, 0xff, 0xff),  /* white */
439     }
440 };
441 
442 static void vga_putcharxy(QemuConsole *s, int x, int y, int ch,
443                           TextAttributes *t_attrib)
444 {
445     static pixman_image_t *glyphs[256];
446     DisplaySurface *surface = qemu_console_surface(s);
447     pixman_color_t fgcol, bgcol;
448 
449     if (t_attrib->invers) {
450         bgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
451         fgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
452     } else {
453         fgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
454         bgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
455     }
456 
457     if (!glyphs[ch]) {
458         glyphs[ch] = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, ch);
459     }
460     qemu_pixman_glyph_render(glyphs[ch], surface->image,
461                              &fgcol, &bgcol, x, y, FONT_WIDTH, FONT_HEIGHT);
462 }
463 
464 static void text_console_resize(QemuConsole *s)
465 {
466     TextCell *cells, *c, *c1;
467     int w1, x, y, last_width;
468 
469     last_width = s->width;
470     s->width = surface_width(s->surface) / FONT_WIDTH;
471     s->height = surface_height(s->surface) / FONT_HEIGHT;
472 
473     w1 = last_width;
474     if (s->width < w1)
475         w1 = s->width;
476 
477     cells = g_new(TextCell, s->width * s->total_height + 1);
478     for(y = 0; y < s->total_height; y++) {
479         c = &cells[y * s->width];
480         if (w1 > 0) {
481             c1 = &s->cells[y * last_width];
482             for(x = 0; x < w1; x++) {
483                 *c++ = *c1++;
484             }
485         }
486         for(x = w1; x < s->width; x++) {
487             c->ch = ' ';
488             c->t_attrib = s->t_attrib_default;
489             c++;
490         }
491     }
492     g_free(s->cells);
493     s->cells = cells;
494 }
495 
496 static inline void text_update_xy(QemuConsole *s, int x, int y)
497 {
498     s->text_x[0] = MIN(s->text_x[0], x);
499     s->text_x[1] = MAX(s->text_x[1], x);
500     s->text_y[0] = MIN(s->text_y[0], y);
501     s->text_y[1] = MAX(s->text_y[1], y);
502 }
503 
504 static void invalidate_xy(QemuConsole *s, int x, int y)
505 {
506     if (!qemu_console_is_visible(s)) {
507         return;
508     }
509     if (s->update_x0 > x * FONT_WIDTH)
510         s->update_x0 = x * FONT_WIDTH;
511     if (s->update_y0 > y * FONT_HEIGHT)
512         s->update_y0 = y * FONT_HEIGHT;
513     if (s->update_x1 < (x + 1) * FONT_WIDTH)
514         s->update_x1 = (x + 1) * FONT_WIDTH;
515     if (s->update_y1 < (y + 1) * FONT_HEIGHT)
516         s->update_y1 = (y + 1) * FONT_HEIGHT;
517 }
518 
519 static void update_xy(QemuConsole *s, int x, int y)
520 {
521     TextCell *c;
522     int y1, y2;
523 
524     if (s->ds->have_text) {
525         text_update_xy(s, x, y);
526     }
527 
528     y1 = (s->y_base + y) % s->total_height;
529     y2 = y1 - s->y_displayed;
530     if (y2 < 0) {
531         y2 += s->total_height;
532     }
533     if (y2 < s->height) {
534         if (x >= s->width) {
535             x = s->width - 1;
536         }
537         c = &s->cells[y1 * s->width + x];
538         vga_putcharxy(s, x, y2, c->ch,
539                       &(c->t_attrib));
540         invalidate_xy(s, x, y2);
541     }
542 }
543 
544 static void console_show_cursor(QemuConsole *s, int show)
545 {
546     TextCell *c;
547     int y, y1;
548     int x = s->x;
549 
550     if (s->ds->have_text) {
551         s->cursor_invalidate = 1;
552     }
553 
554     if (x >= s->width) {
555         x = s->width - 1;
556     }
557     y1 = (s->y_base + s->y) % s->total_height;
558     y = y1 - s->y_displayed;
559     if (y < 0) {
560         y += s->total_height;
561     }
562     if (y < s->height) {
563         c = &s->cells[y1 * s->width + x];
564         if (show && cursor_visible_phase) {
565             TextAttributes t_attrib = s->t_attrib_default;
566             t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
567             vga_putcharxy(s, x, y, c->ch, &t_attrib);
568         } else {
569             vga_putcharxy(s, x, y, c->ch, &(c->t_attrib));
570         }
571         invalidate_xy(s, x, y);
572     }
573 }
574 
575 static void console_refresh(QemuConsole *s)
576 {
577     DisplaySurface *surface = qemu_console_surface(s);
578     TextCell *c;
579     int x, y, y1;
580 
581     if (s->ds->have_text) {
582         s->text_x[0] = 0;
583         s->text_y[0] = 0;
584         s->text_x[1] = s->width - 1;
585         s->text_y[1] = s->height - 1;
586         s->cursor_invalidate = 1;
587     }
588 
589     vga_fill_rect(s, 0, 0, surface_width(surface), surface_height(surface),
590                   color_table_rgb[0][QEMU_COLOR_BLACK]);
591     y1 = s->y_displayed;
592     for (y = 0; y < s->height; y++) {
593         c = s->cells + y1 * s->width;
594         for (x = 0; x < s->width; x++) {
595             vga_putcharxy(s, x, y, c->ch,
596                           &(c->t_attrib));
597             c++;
598         }
599         if (++y1 == s->total_height) {
600             y1 = 0;
601         }
602     }
603     console_show_cursor(s, 1);
604     dpy_gfx_update(s, 0, 0,
605                    surface_width(surface), surface_height(surface));
606 }
607 
608 static void console_scroll(QemuConsole *s, int ydelta)
609 {
610     int i, y1;
611 
612     if (ydelta > 0) {
613         for(i = 0; i < ydelta; i++) {
614             if (s->y_displayed == s->y_base)
615                 break;
616             if (++s->y_displayed == s->total_height)
617                 s->y_displayed = 0;
618         }
619     } else {
620         ydelta = -ydelta;
621         i = s->backscroll_height;
622         if (i > s->total_height - s->height)
623             i = s->total_height - s->height;
624         y1 = s->y_base - i;
625         if (y1 < 0)
626             y1 += s->total_height;
627         for(i = 0; i < ydelta; i++) {
628             if (s->y_displayed == y1)
629                 break;
630             if (--s->y_displayed < 0)
631                 s->y_displayed = s->total_height - 1;
632         }
633     }
634     console_refresh(s);
635 }
636 
637 static void console_put_lf(QemuConsole *s)
638 {
639     TextCell *c;
640     int x, y1;
641 
642     s->y++;
643     if (s->y >= s->height) {
644         s->y = s->height - 1;
645 
646         if (s->y_displayed == s->y_base) {
647             if (++s->y_displayed == s->total_height)
648                 s->y_displayed = 0;
649         }
650         if (++s->y_base == s->total_height)
651             s->y_base = 0;
652         if (s->backscroll_height < s->total_height)
653             s->backscroll_height++;
654         y1 = (s->y_base + s->height - 1) % s->total_height;
655         c = &s->cells[y1 * s->width];
656         for(x = 0; x < s->width; x++) {
657             c->ch = ' ';
658             c->t_attrib = s->t_attrib_default;
659             c++;
660         }
661         if (s->y_displayed == s->y_base) {
662             if (s->ds->have_text) {
663                 s->text_x[0] = 0;
664                 s->text_y[0] = 0;
665                 s->text_x[1] = s->width - 1;
666                 s->text_y[1] = s->height - 1;
667             }
668 
669             vga_bitblt(s, 0, FONT_HEIGHT, 0, 0,
670                        s->width * FONT_WIDTH,
671                        (s->height - 1) * FONT_HEIGHT);
672             vga_fill_rect(s, 0, (s->height - 1) * FONT_HEIGHT,
673                           s->width * FONT_WIDTH, FONT_HEIGHT,
674                           color_table_rgb[0][s->t_attrib_default.bgcol]);
675             s->update_x0 = 0;
676             s->update_y0 = 0;
677             s->update_x1 = s->width * FONT_WIDTH;
678             s->update_y1 = s->height * FONT_HEIGHT;
679         }
680     }
681 }
682 
683 /* Set console attributes depending on the current escape codes.
684  * NOTE: I know this code is not very efficient (checking every color for it
685  * self) but it is more readable and better maintainable.
686  */
687 static void console_handle_escape(QemuConsole *s)
688 {
689     int i;
690 
691     for (i=0; i<s->nb_esc_params; i++) {
692         switch (s->esc_params[i]) {
693             case 0: /* reset all console attributes to default */
694                 s->t_attrib = s->t_attrib_default;
695                 break;
696             case 1:
697                 s->t_attrib.bold = 1;
698                 break;
699             case 4:
700                 s->t_attrib.uline = 1;
701                 break;
702             case 5:
703                 s->t_attrib.blink = 1;
704                 break;
705             case 7:
706                 s->t_attrib.invers = 1;
707                 break;
708             case 8:
709                 s->t_attrib.unvisible = 1;
710                 break;
711             case 22:
712                 s->t_attrib.bold = 0;
713                 break;
714             case 24:
715                 s->t_attrib.uline = 0;
716                 break;
717             case 25:
718                 s->t_attrib.blink = 0;
719                 break;
720             case 27:
721                 s->t_attrib.invers = 0;
722                 break;
723             case 28:
724                 s->t_attrib.unvisible = 0;
725                 break;
726             /* set foreground color */
727             case 30:
728                 s->t_attrib.fgcol = QEMU_COLOR_BLACK;
729                 break;
730             case 31:
731                 s->t_attrib.fgcol = QEMU_COLOR_RED;
732                 break;
733             case 32:
734                 s->t_attrib.fgcol = QEMU_COLOR_GREEN;
735                 break;
736             case 33:
737                 s->t_attrib.fgcol = QEMU_COLOR_YELLOW;
738                 break;
739             case 34:
740                 s->t_attrib.fgcol = QEMU_COLOR_BLUE;
741                 break;
742             case 35:
743                 s->t_attrib.fgcol = QEMU_COLOR_MAGENTA;
744                 break;
745             case 36:
746                 s->t_attrib.fgcol = QEMU_COLOR_CYAN;
747                 break;
748             case 37:
749                 s->t_attrib.fgcol = QEMU_COLOR_WHITE;
750                 break;
751             /* set background color */
752             case 40:
753                 s->t_attrib.bgcol = QEMU_COLOR_BLACK;
754                 break;
755             case 41:
756                 s->t_attrib.bgcol = QEMU_COLOR_RED;
757                 break;
758             case 42:
759                 s->t_attrib.bgcol = QEMU_COLOR_GREEN;
760                 break;
761             case 43:
762                 s->t_attrib.bgcol = QEMU_COLOR_YELLOW;
763                 break;
764             case 44:
765                 s->t_attrib.bgcol = QEMU_COLOR_BLUE;
766                 break;
767             case 45:
768                 s->t_attrib.bgcol = QEMU_COLOR_MAGENTA;
769                 break;
770             case 46:
771                 s->t_attrib.bgcol = QEMU_COLOR_CYAN;
772                 break;
773             case 47:
774                 s->t_attrib.bgcol = QEMU_COLOR_WHITE;
775                 break;
776         }
777     }
778 }
779 
780 static void console_clear_xy(QemuConsole *s, int x, int y)
781 {
782     int y1 = (s->y_base + y) % s->total_height;
783     if (x >= s->width) {
784         x = s->width - 1;
785     }
786     TextCell *c = &s->cells[y1 * s->width + x];
787     c->ch = ' ';
788     c->t_attrib = s->t_attrib_default;
789     update_xy(s, x, y);
790 }
791 
792 static void console_put_one(QemuConsole *s, int ch)
793 {
794     TextCell *c;
795     int y1;
796     if (s->x >= s->width) {
797         /* line wrap */
798         s->x = 0;
799         console_put_lf(s);
800     }
801     y1 = (s->y_base + s->y) % s->total_height;
802     c = &s->cells[y1 * s->width + s->x];
803     c->ch = ch;
804     c->t_attrib = s->t_attrib;
805     update_xy(s, s->x, s->y);
806     s->x++;
807 }
808 
809 static void console_respond_str(QemuConsole *s, const char *buf)
810 {
811     while (*buf) {
812         console_put_one(s, *buf);
813         buf++;
814     }
815 }
816 
817 /* set cursor, checking bounds */
818 static void set_cursor(QemuConsole *s, int x, int y)
819 {
820     if (x < 0) {
821         x = 0;
822     }
823     if (y < 0) {
824         y = 0;
825     }
826     if (y >= s->height) {
827         y = s->height - 1;
828     }
829     if (x >= s->width) {
830         x = s->width - 1;
831     }
832 
833     s->x = x;
834     s->y = y;
835 }
836 
837 static void console_putchar(QemuConsole *s, int ch)
838 {
839     int i;
840     int x, y;
841     char response[40];
842 
843     switch(s->state) {
844     case TTY_STATE_NORM:
845         switch(ch) {
846         case '\r':  /* carriage return */
847             s->x = 0;
848             break;
849         case '\n':  /* newline */
850             console_put_lf(s);
851             break;
852         case '\b':  /* backspace */
853             if (s->x > 0)
854                 s->x--;
855             break;
856         case '\t':  /* tabspace */
857             if (s->x + (8 - (s->x % 8)) > s->width) {
858                 s->x = 0;
859                 console_put_lf(s);
860             } else {
861                 s->x = s->x + (8 - (s->x % 8));
862             }
863             break;
864         case '\a':  /* alert aka. bell */
865             /* TODO: has to be implemented */
866             break;
867         case 14:
868             /* SI (shift in), character set 0 (ignored) */
869             break;
870         case 15:
871             /* SO (shift out), character set 1 (ignored) */
872             break;
873         case 27:    /* esc (introducing an escape sequence) */
874             s->state = TTY_STATE_ESC;
875             break;
876         default:
877             console_put_one(s, ch);
878             break;
879         }
880         break;
881     case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
882         if (ch == '[') {
883             for(i=0;i<MAX_ESC_PARAMS;i++)
884                 s->esc_params[i] = 0;
885             s->nb_esc_params = 0;
886             s->state = TTY_STATE_CSI;
887         } else {
888             s->state = TTY_STATE_NORM;
889         }
890         break;
891     case TTY_STATE_CSI: /* handle escape sequence parameters */
892         if (ch >= '0' && ch <= '9') {
893             if (s->nb_esc_params < MAX_ESC_PARAMS) {
894                 int *param = &s->esc_params[s->nb_esc_params];
895                 int digit = (ch - '0');
896 
897                 *param = (*param <= (INT_MAX - digit) / 10) ?
898                          *param * 10 + digit : INT_MAX;
899             }
900         } else {
901             if (s->nb_esc_params < MAX_ESC_PARAMS)
902                 s->nb_esc_params++;
903             if (ch == ';' || ch == '?') {
904                 break;
905             }
906             trace_console_putchar_csi(s->esc_params[0], s->esc_params[1],
907                                       ch, s->nb_esc_params);
908             s->state = TTY_STATE_NORM;
909             switch(ch) {
910             case 'A':
911                 /* move cursor up */
912                 if (s->esc_params[0] == 0) {
913                     s->esc_params[0] = 1;
914                 }
915                 set_cursor(s, s->x, s->y - s->esc_params[0]);
916                 break;
917             case 'B':
918                 /* move cursor down */
919                 if (s->esc_params[0] == 0) {
920                     s->esc_params[0] = 1;
921                 }
922                 set_cursor(s, s->x, s->y + s->esc_params[0]);
923                 break;
924             case 'C':
925                 /* move cursor right */
926                 if (s->esc_params[0] == 0) {
927                     s->esc_params[0] = 1;
928                 }
929                 set_cursor(s, s->x + s->esc_params[0], s->y);
930                 break;
931             case 'D':
932                 /* move cursor left */
933                 if (s->esc_params[0] == 0) {
934                     s->esc_params[0] = 1;
935                 }
936                 set_cursor(s, s->x - s->esc_params[0], s->y);
937                 break;
938             case 'G':
939                 /* move cursor to column */
940                 set_cursor(s, s->esc_params[0] - 1, s->y);
941                 break;
942             case 'f':
943             case 'H':
944                 /* move cursor to row, column */
945                 set_cursor(s, s->esc_params[1] - 1, s->esc_params[0] - 1);
946                 break;
947             case 'J':
948                 switch (s->esc_params[0]) {
949                 case 0:
950                     /* clear to end of screen */
951                     for (y = s->y; y < s->height; y++) {
952                         for (x = 0; x < s->width; x++) {
953                             if (y == s->y && x < s->x) {
954                                 continue;
955                             }
956                             console_clear_xy(s, x, y);
957                         }
958                     }
959                     break;
960                 case 1:
961                     /* clear from beginning of screen */
962                     for (y = 0; y <= s->y; y++) {
963                         for (x = 0; x < s->width; x++) {
964                             if (y == s->y && x > s->x) {
965                                 break;
966                             }
967                             console_clear_xy(s, x, y);
968                         }
969                     }
970                     break;
971                 case 2:
972                     /* clear entire screen */
973                     for (y = 0; y <= s->height; y++) {
974                         for (x = 0; x < s->width; x++) {
975                             console_clear_xy(s, x, y);
976                         }
977                     }
978                     break;
979                 }
980                 break;
981             case 'K':
982                 switch (s->esc_params[0]) {
983                 case 0:
984                     /* clear to eol */
985                     for(x = s->x; x < s->width; x++) {
986                         console_clear_xy(s, x, s->y);
987                     }
988                     break;
989                 case 1:
990                     /* clear from beginning of line */
991                     for (x = 0; x <= s->x && x < s->width; x++) {
992                         console_clear_xy(s, x, s->y);
993                     }
994                     break;
995                 case 2:
996                     /* clear entire line */
997                     for(x = 0; x < s->width; x++) {
998                         console_clear_xy(s, x, s->y);
999                     }
1000                     break;
1001                 }
1002                 break;
1003             case 'm':
1004                 console_handle_escape(s);
1005                 break;
1006             case 'n':
1007                 switch (s->esc_params[0]) {
1008                 case 5:
1009                     /* report console status (always succeed)*/
1010                     console_respond_str(s, "\033[0n");
1011                     break;
1012                 case 6:
1013                     /* report cursor position */
1014                     sprintf(response, "\033[%d;%dR",
1015                            (s->y_base + s->y) % s->total_height + 1,
1016                             s->x + 1);
1017                     console_respond_str(s, response);
1018                     break;
1019                 }
1020                 break;
1021             case 's':
1022                 /* save cursor position */
1023                 s->x_saved = s->x;
1024                 s->y_saved = s->y;
1025                 break;
1026             case 'u':
1027                 /* restore cursor position */
1028                 s->x = s->x_saved;
1029                 s->y = s->y_saved;
1030                 break;
1031             default:
1032                 trace_console_putchar_unhandled(ch);
1033                 break;
1034             }
1035             break;
1036         }
1037     }
1038 }
1039 
1040 void console_select(unsigned int index)
1041 {
1042     DisplayChangeListener *dcl;
1043     QemuConsole *s;
1044 
1045     trace_console_select(index);
1046     s = qemu_console_lookup_by_index(index);
1047     if (s) {
1048         DisplayState *ds = s->ds;
1049 
1050         active_console = s;
1051         if (ds->have_gfx) {
1052             QLIST_FOREACH(dcl, &ds->listeners, next) {
1053                 if (dcl->con != NULL) {
1054                     continue;
1055                 }
1056                 if (dcl->ops->dpy_gfx_switch) {
1057                     dcl->ops->dpy_gfx_switch(dcl, s->surface);
1058                 }
1059             }
1060             if (s->surface) {
1061                 dpy_gfx_update(s, 0, 0, surface_width(s->surface),
1062                                surface_height(s->surface));
1063             }
1064         }
1065         if (ds->have_text) {
1066             dpy_text_resize(s, s->width, s->height);
1067         }
1068         text_console_update_cursor(NULL);
1069     }
1070 }
1071 
1072 struct VCChardev {
1073     Chardev parent;
1074     QemuConsole *console;
1075 };
1076 typedef struct VCChardev VCChardev;
1077 
1078 #define TYPE_CHARDEV_VC "chardev-vc"
1079 DECLARE_INSTANCE_CHECKER(VCChardev, VC_CHARDEV,
1080                          TYPE_CHARDEV_VC)
1081 
1082 static int vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
1083 {
1084     VCChardev *drv = VC_CHARDEV(chr);
1085     QemuConsole *s = drv->console;
1086     int i;
1087 
1088     if (!s->ds) {
1089         return 0;
1090     }
1091 
1092     s->update_x0 = s->width * FONT_WIDTH;
1093     s->update_y0 = s->height * FONT_HEIGHT;
1094     s->update_x1 = 0;
1095     s->update_y1 = 0;
1096     console_show_cursor(s, 0);
1097     for(i = 0; i < len; i++) {
1098         console_putchar(s, buf[i]);
1099     }
1100     console_show_cursor(s, 1);
1101     if (s->ds->have_gfx && s->update_x0 < s->update_x1) {
1102         dpy_gfx_update(s, s->update_x0, s->update_y0,
1103                        s->update_x1 - s->update_x0,
1104                        s->update_y1 - s->update_y0);
1105     }
1106     return len;
1107 }
1108 
1109 static void kbd_send_chars(QemuConsole *s)
1110 {
1111     uint32_t len, avail;
1112 
1113     len = qemu_chr_be_can_write(s->chr);
1114     avail = fifo8_num_used(&s->out_fifo);
1115     while (len > 0 && avail > 0) {
1116         const uint8_t *buf;
1117         uint32_t size;
1118 
1119         buf = fifo8_pop_buf(&s->out_fifo, MIN(len, avail), &size);
1120         qemu_chr_be_write(s->chr, (uint8_t *)buf, size);
1121         len = qemu_chr_be_can_write(s->chr);
1122         avail -= size;
1123     }
1124 }
1125 
1126 /* called when an ascii key is pressed */
1127 void kbd_put_keysym_console(QemuConsole *s, int keysym)
1128 {
1129     uint8_t buf[16], *q;
1130     int c;
1131     uint32_t num_free;
1132 
1133     if (!s || (s->console_type == GRAPHIC_CONSOLE))
1134         return;
1135 
1136     switch(keysym) {
1137     case QEMU_KEY_CTRL_UP:
1138         console_scroll(s, -1);
1139         break;
1140     case QEMU_KEY_CTRL_DOWN:
1141         console_scroll(s, 1);
1142         break;
1143     case QEMU_KEY_CTRL_PAGEUP:
1144         console_scroll(s, -10);
1145         break;
1146     case QEMU_KEY_CTRL_PAGEDOWN:
1147         console_scroll(s, 10);
1148         break;
1149     default:
1150         /* convert the QEMU keysym to VT100 key string */
1151         q = buf;
1152         if (keysym >= 0xe100 && keysym <= 0xe11f) {
1153             *q++ = '\033';
1154             *q++ = '[';
1155             c = keysym - 0xe100;
1156             if (c >= 10)
1157                 *q++ = '0' + (c / 10);
1158             *q++ = '0' + (c % 10);
1159             *q++ = '~';
1160         } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1161             *q++ = '\033';
1162             *q++ = '[';
1163             *q++ = keysym & 0xff;
1164         } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
1165             vc_chr_write(s->chr, (const uint8_t *) "\r", 1);
1166             *q++ = '\n';
1167         } else {
1168             *q++ = keysym;
1169         }
1170         if (s->echo) {
1171             vc_chr_write(s->chr, buf, q - buf);
1172         }
1173         num_free = fifo8_num_free(&s->out_fifo);
1174         fifo8_push_all(&s->out_fifo, buf, MIN(num_free, q - buf));
1175         kbd_send_chars(s);
1176         break;
1177     }
1178 }
1179 
1180 static const int qcode_to_keysym[Q_KEY_CODE__MAX] = {
1181     [Q_KEY_CODE_UP]     = QEMU_KEY_UP,
1182     [Q_KEY_CODE_DOWN]   = QEMU_KEY_DOWN,
1183     [Q_KEY_CODE_RIGHT]  = QEMU_KEY_RIGHT,
1184     [Q_KEY_CODE_LEFT]   = QEMU_KEY_LEFT,
1185     [Q_KEY_CODE_HOME]   = QEMU_KEY_HOME,
1186     [Q_KEY_CODE_END]    = QEMU_KEY_END,
1187     [Q_KEY_CODE_PGUP]   = QEMU_KEY_PAGEUP,
1188     [Q_KEY_CODE_PGDN]   = QEMU_KEY_PAGEDOWN,
1189     [Q_KEY_CODE_DELETE] = QEMU_KEY_DELETE,
1190     [Q_KEY_CODE_BACKSPACE] = QEMU_KEY_BACKSPACE,
1191 };
1192 
1193 static const int ctrl_qcode_to_keysym[Q_KEY_CODE__MAX] = {
1194     [Q_KEY_CODE_UP]     = QEMU_KEY_CTRL_UP,
1195     [Q_KEY_CODE_DOWN]   = QEMU_KEY_CTRL_DOWN,
1196     [Q_KEY_CODE_RIGHT]  = QEMU_KEY_CTRL_RIGHT,
1197     [Q_KEY_CODE_LEFT]   = QEMU_KEY_CTRL_LEFT,
1198     [Q_KEY_CODE_HOME]   = QEMU_KEY_CTRL_HOME,
1199     [Q_KEY_CODE_END]    = QEMU_KEY_CTRL_END,
1200     [Q_KEY_CODE_PGUP]   = QEMU_KEY_CTRL_PAGEUP,
1201     [Q_KEY_CODE_PGDN]   = QEMU_KEY_CTRL_PAGEDOWN,
1202 };
1203 
1204 bool kbd_put_qcode_console(QemuConsole *s, int qcode, bool ctrl)
1205 {
1206     int keysym;
1207 
1208     keysym = ctrl ? ctrl_qcode_to_keysym[qcode] : qcode_to_keysym[qcode];
1209     if (keysym == 0) {
1210         return false;
1211     }
1212     kbd_put_keysym_console(s, keysym);
1213     return true;
1214 }
1215 
1216 void kbd_put_string_console(QemuConsole *s, const char *str, int len)
1217 {
1218     int i;
1219 
1220     for (i = 0; i < len && str[i]; i++) {
1221         kbd_put_keysym_console(s, str[i]);
1222     }
1223 }
1224 
1225 void kbd_put_keysym(int keysym)
1226 {
1227     kbd_put_keysym_console(active_console, keysym);
1228 }
1229 
1230 static void text_console_invalidate(void *opaque)
1231 {
1232     QemuConsole *s = (QemuConsole *) opaque;
1233 
1234     if (s->ds->have_text && s->console_type == TEXT_CONSOLE) {
1235         text_console_resize(s);
1236     }
1237     console_refresh(s);
1238 }
1239 
1240 static void text_console_update(void *opaque, console_ch_t *chardata)
1241 {
1242     QemuConsole *s = (QemuConsole *) opaque;
1243     int i, j, src;
1244 
1245     if (s->text_x[0] <= s->text_x[1]) {
1246         src = (s->y_base + s->text_y[0]) * s->width;
1247         chardata += s->text_y[0] * s->width;
1248         for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1249             for (j = 0; j < s->width; j++, src++) {
1250                 console_write_ch(chardata ++,
1251                                  ATTR2CHTYPE(s->cells[src].ch,
1252                                              s->cells[src].t_attrib.fgcol,
1253                                              s->cells[src].t_attrib.bgcol,
1254                                              s->cells[src].t_attrib.bold));
1255             }
1256         dpy_text_update(s, s->text_x[0], s->text_y[0],
1257                         s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1258         s->text_x[0] = s->width;
1259         s->text_y[0] = s->height;
1260         s->text_x[1] = 0;
1261         s->text_y[1] = 0;
1262     }
1263     if (s->cursor_invalidate) {
1264         dpy_text_cursor(s, s->x, s->y);
1265         s->cursor_invalidate = 0;
1266     }
1267 }
1268 
1269 static QemuConsole *new_console(DisplayState *ds, console_type_t console_type,
1270                                 uint32_t head)
1271 {
1272     Object *obj;
1273     QemuConsole *s;
1274     int i;
1275 
1276     obj = object_new(TYPE_QEMU_CONSOLE);
1277     s = QEMU_CONSOLE(obj);
1278     qemu_co_queue_init(&s->dump_queue);
1279     s->head = head;
1280     object_property_add_link(obj, "device", TYPE_DEVICE,
1281                              (Object **)&s->device,
1282                              object_property_allow_set_link,
1283                              OBJ_PROP_LINK_STRONG);
1284     object_property_add_uint32_ptr(obj, "head", &s->head,
1285                                    OBJ_PROP_FLAG_READ);
1286 
1287     if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1288         (console_type == GRAPHIC_CONSOLE))) {
1289         active_console = s;
1290     }
1291     s->ds = ds;
1292     s->console_type = console_type;
1293     s->window_id = -1;
1294 
1295     if (QTAILQ_EMPTY(&consoles)) {
1296         s->index = 0;
1297         QTAILQ_INSERT_TAIL(&consoles, s, next);
1298     } else if (console_type != GRAPHIC_CONSOLE || phase_check(PHASE_MACHINE_READY)) {
1299         QemuConsole *last = QTAILQ_LAST(&consoles);
1300         s->index = last->index + 1;
1301         QTAILQ_INSERT_TAIL(&consoles, s, next);
1302     } else {
1303         /*
1304          * HACK: Put graphical consoles before text consoles.
1305          *
1306          * Only do that for coldplugged devices.  After initial device
1307          * initialization we will not renumber the consoles any more.
1308          */
1309         QemuConsole *c = QTAILQ_FIRST(&consoles);
1310 
1311         while (QTAILQ_NEXT(c, next) != NULL &&
1312                c->console_type == GRAPHIC_CONSOLE) {
1313             c = QTAILQ_NEXT(c, next);
1314         }
1315         if (c->console_type == GRAPHIC_CONSOLE) {
1316             /* have no text consoles */
1317             s->index = c->index + 1;
1318             QTAILQ_INSERT_AFTER(&consoles, c, s, next);
1319         } else {
1320             s->index = c->index;
1321             QTAILQ_INSERT_BEFORE(c, s, next);
1322             /* renumber text consoles */
1323             for (i = s->index + 1; c != NULL; c = QTAILQ_NEXT(c, next), i++) {
1324                 c->index = i;
1325             }
1326         }
1327     }
1328     return s;
1329 }
1330 
1331 DisplaySurface *qemu_create_displaysurface(int width, int height)
1332 {
1333     DisplaySurface *surface = g_new0(DisplaySurface, 1);
1334 
1335     trace_displaysurface_create(surface, width, height);
1336     surface->format = PIXMAN_x8r8g8b8;
1337     surface->image = pixman_image_create_bits(surface->format,
1338                                               width, height,
1339                                               NULL, width * 4);
1340     assert(surface->image != NULL);
1341     surface->flags = QEMU_ALLOCATED_FLAG;
1342 
1343     return surface;
1344 }
1345 
1346 DisplaySurface *qemu_create_displaysurface_from(int width, int height,
1347                                                 pixman_format_code_t format,
1348                                                 int linesize, uint8_t *data)
1349 {
1350     DisplaySurface *surface = g_new0(DisplaySurface, 1);
1351 
1352     trace_displaysurface_create_from(surface, width, height, format);
1353     surface->format = format;
1354     surface->image = pixman_image_create_bits(surface->format,
1355                                               width, height,
1356                                               (void *)data, linesize);
1357     assert(surface->image != NULL);
1358 
1359     return surface;
1360 }
1361 
1362 DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image)
1363 {
1364     DisplaySurface *surface = g_new0(DisplaySurface, 1);
1365 
1366     trace_displaysurface_create_pixman(surface);
1367     surface->format = pixman_image_get_format(image);
1368     surface->image = pixman_image_ref(image);
1369 
1370     return surface;
1371 }
1372 
1373 DisplaySurface *qemu_create_placeholder_surface(int w, int h,
1374                                                 const char *msg)
1375 {
1376     DisplaySurface *surface = qemu_create_displaysurface(w, h);
1377     pixman_color_t bg = color_table_rgb[0][QEMU_COLOR_BLACK];
1378     pixman_color_t fg = color_table_rgb[0][QEMU_COLOR_WHITE];
1379     pixman_image_t *glyph;
1380     int len, x, y, i;
1381 
1382     len = strlen(msg);
1383     x = (w / FONT_WIDTH  - len) / 2;
1384     y = (h / FONT_HEIGHT - 1)   / 2;
1385     for (i = 0; i < len; i++) {
1386         glyph = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, msg[i]);
1387         qemu_pixman_glyph_render(glyph, surface->image, &fg, &bg,
1388                                  x+i, y, FONT_WIDTH, FONT_HEIGHT);
1389         qemu_pixman_image_unref(glyph);
1390     }
1391     surface->flags |= QEMU_PLACEHOLDER_FLAG;
1392     return surface;
1393 }
1394 
1395 void qemu_free_displaysurface(DisplaySurface *surface)
1396 {
1397     if (surface == NULL) {
1398         return;
1399     }
1400     trace_displaysurface_free(surface);
1401     qemu_pixman_image_unref(surface->image);
1402     g_free(surface);
1403 }
1404 
1405 bool console_has_gl(QemuConsole *con)
1406 {
1407     return con->gl != NULL;
1408 }
1409 
1410 static bool displaychangelistener_has_dmabuf(DisplayChangeListener *dcl)
1411 {
1412     if (dcl->ops->dpy_has_dmabuf) {
1413         return dcl->ops->dpy_has_dmabuf(dcl);
1414     }
1415 
1416     if (dcl->ops->dpy_gl_scanout_dmabuf) {
1417         return true;
1418     }
1419 
1420     return false;
1421 }
1422 
1423 static bool dpy_compatible_with(QemuConsole *con,
1424                                 DisplayChangeListener *dcl, Error **errp)
1425 {
1426     int flags;
1427 
1428     flags = con->hw_ops->get_flags ? con->hw_ops->get_flags(con->hw) : 0;
1429 
1430     if (flags & GRAPHIC_FLAGS_GL &&
1431         !console_has_gl(con)) {
1432         error_setg(errp, "The console requires a GL context.");
1433         return false;
1434 
1435     }
1436 
1437     if (flags & GRAPHIC_FLAGS_DMABUF &&
1438         !displaychangelistener_has_dmabuf(dcl)) {
1439         error_setg(errp, "The console requires display DMABUF support.");
1440         return false;
1441     }
1442 
1443     return true;
1444 }
1445 
1446 void register_displaychangelistener(DisplayChangeListener *dcl)
1447 {
1448     static const char nodev[] =
1449         "This VM has no graphic display device.";
1450     static DisplaySurface *dummy;
1451     QemuConsole *con;
1452 
1453     assert(!dcl->ds);
1454 
1455     if (dcl->ops->dpy_gl_ctx_create) {
1456         /* display has opengl support */
1457         assert(dcl->con);
1458         if (dcl->con->gl) {
1459             fprintf(stderr, "can't register two opengl displays (%s, %s)\n",
1460                     dcl->ops->dpy_name, dcl->con->gl->ops->dpy_name);
1461             exit(1);
1462         }
1463         dcl->con->gl = dcl;
1464     }
1465 
1466     if (dcl->con) {
1467         dpy_compatible_with(dcl->con, dcl, &error_fatal);
1468     }
1469 
1470     trace_displaychangelistener_register(dcl, dcl->ops->dpy_name);
1471     dcl->ds = get_alloc_displaystate();
1472     QLIST_INSERT_HEAD(&dcl->ds->listeners, dcl, next);
1473     gui_setup_refresh(dcl->ds);
1474     if (dcl->con) {
1475         dcl->con->dcls++;
1476         con = dcl->con;
1477     } else {
1478         con = active_console;
1479     }
1480     if (dcl->ops->dpy_gfx_switch) {
1481         if (con) {
1482             dcl->ops->dpy_gfx_switch(dcl, con->surface);
1483         } else {
1484             if (!dummy) {
1485                 dummy = qemu_create_placeholder_surface(640, 480, nodev);
1486             }
1487             dcl->ops->dpy_gfx_switch(dcl, dummy);
1488         }
1489     }
1490     text_console_update_cursor(NULL);
1491 }
1492 
1493 void update_displaychangelistener(DisplayChangeListener *dcl,
1494                                   uint64_t interval)
1495 {
1496     DisplayState *ds = dcl->ds;
1497 
1498     dcl->update_interval = interval;
1499     if (!ds->refreshing && ds->update_interval > interval) {
1500         timer_mod(ds->gui_timer, ds->last_update + interval);
1501     }
1502 }
1503 
1504 void unregister_displaychangelistener(DisplayChangeListener *dcl)
1505 {
1506     DisplayState *ds = dcl->ds;
1507     trace_displaychangelistener_unregister(dcl, dcl->ops->dpy_name);
1508     if (dcl->con) {
1509         dcl->con->dcls--;
1510     }
1511     QLIST_REMOVE(dcl, next);
1512     dcl->ds = NULL;
1513     gui_setup_refresh(ds);
1514 }
1515 
1516 static void dpy_set_ui_info_timer(void *opaque)
1517 {
1518     QemuConsole *con = opaque;
1519 
1520     con->hw_ops->ui_info(con->hw, con->head, &con->ui_info);
1521 }
1522 
1523 bool dpy_ui_info_supported(QemuConsole *con)
1524 {
1525     if (con == NULL) {
1526         con = active_console;
1527     }
1528 
1529     return con->hw_ops->ui_info != NULL;
1530 }
1531 
1532 const QemuUIInfo *dpy_get_ui_info(const QemuConsole *con)
1533 {
1534     if (con == NULL) {
1535         con = active_console;
1536     }
1537 
1538     return &con->ui_info;
1539 }
1540 
1541 int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info)
1542 {
1543     if (con == NULL) {
1544         con = active_console;
1545     }
1546 
1547     if (!dpy_ui_info_supported(con)) {
1548         return -1;
1549     }
1550     if (memcmp(&con->ui_info, info, sizeof(con->ui_info)) == 0) {
1551         /* nothing changed -- ignore */
1552         return 0;
1553     }
1554 
1555     /*
1556      * Typically we get a flood of these as the user resizes the window.
1557      * Wait until the dust has settled (one second without updates), then
1558      * go notify the guest.
1559      */
1560     con->ui_info = *info;
1561     timer_mod(con->ui_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
1562     return 0;
1563 }
1564 
1565 void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
1566 {
1567     DisplayState *s = con->ds;
1568     DisplayChangeListener *dcl;
1569     int width = w;
1570     int height = h;
1571 
1572     if (con->surface) {
1573         width = surface_width(con->surface);
1574         height = surface_height(con->surface);
1575     }
1576     x = MAX(x, 0);
1577     y = MAX(y, 0);
1578     x = MIN(x, width);
1579     y = MIN(y, height);
1580     w = MIN(w, width - x);
1581     h = MIN(h, height - y);
1582 
1583     if (!qemu_console_is_visible(con)) {
1584         return;
1585     }
1586     QLIST_FOREACH(dcl, &s->listeners, next) {
1587         if (con != (dcl->con ? dcl->con : active_console)) {
1588             continue;
1589         }
1590         if (dcl->ops->dpy_gfx_update) {
1591             dcl->ops->dpy_gfx_update(dcl, x, y, w, h);
1592         }
1593     }
1594 }
1595 
1596 void dpy_gfx_update_full(QemuConsole *con)
1597 {
1598     if (!con->surface) {
1599         return;
1600     }
1601     dpy_gfx_update(con, 0, 0,
1602                    surface_width(con->surface),
1603                    surface_height(con->surface));
1604 }
1605 
1606 void dpy_gfx_replace_surface(QemuConsole *con,
1607                              DisplaySurface *surface)
1608 {
1609     static const char placeholder_msg[] = "Display output is not active.";
1610     DisplayState *s = con->ds;
1611     DisplaySurface *old_surface = con->surface;
1612     DisplayChangeListener *dcl;
1613     int width;
1614     int height;
1615 
1616     if (!surface) {
1617         if (old_surface) {
1618             width = surface_width(old_surface);
1619             height = surface_height(old_surface);
1620         } else {
1621             width = 640;
1622             height = 480;
1623         }
1624 
1625         surface = qemu_create_placeholder_surface(width, height, placeholder_msg);
1626     }
1627 
1628     assert(old_surface != surface);
1629 
1630     con->surface = surface;
1631     QLIST_FOREACH(dcl, &s->listeners, next) {
1632         if (con != (dcl->con ? dcl->con : active_console)) {
1633             continue;
1634         }
1635         if (dcl->ops->dpy_gfx_switch) {
1636             dcl->ops->dpy_gfx_switch(dcl, surface);
1637         }
1638     }
1639     qemu_free_displaysurface(old_surface);
1640 }
1641 
1642 bool dpy_gfx_check_format(QemuConsole *con,
1643                           pixman_format_code_t format)
1644 {
1645     DisplayChangeListener *dcl;
1646     DisplayState *s = con->ds;
1647 
1648     QLIST_FOREACH(dcl, &s->listeners, next) {
1649         if (dcl->con && dcl->con != con) {
1650             /* dcl bound to another console -> skip */
1651             continue;
1652         }
1653         if (dcl->ops->dpy_gfx_check_format) {
1654             if (!dcl->ops->dpy_gfx_check_format(dcl, format)) {
1655                 return false;
1656             }
1657         } else {
1658             /* default is to allow native 32 bpp only */
1659             if (format != qemu_default_pixman_format(32, true)) {
1660                 return false;
1661             }
1662         }
1663     }
1664     return true;
1665 }
1666 
1667 static void dpy_refresh(DisplayState *s)
1668 {
1669     DisplayChangeListener *dcl;
1670 
1671     QLIST_FOREACH(dcl, &s->listeners, next) {
1672         if (dcl->ops->dpy_refresh) {
1673             dcl->ops->dpy_refresh(dcl);
1674         }
1675     }
1676 }
1677 
1678 void dpy_text_cursor(QemuConsole *con, int x, int y)
1679 {
1680     DisplayState *s = con->ds;
1681     DisplayChangeListener *dcl;
1682 
1683     if (!qemu_console_is_visible(con)) {
1684         return;
1685     }
1686     QLIST_FOREACH(dcl, &s->listeners, next) {
1687         if (con != (dcl->con ? dcl->con : active_console)) {
1688             continue;
1689         }
1690         if (dcl->ops->dpy_text_cursor) {
1691             dcl->ops->dpy_text_cursor(dcl, x, y);
1692         }
1693     }
1694 }
1695 
1696 void dpy_text_update(QemuConsole *con, int x, int y, int w, int h)
1697 {
1698     DisplayState *s = con->ds;
1699     DisplayChangeListener *dcl;
1700 
1701     if (!qemu_console_is_visible(con)) {
1702         return;
1703     }
1704     QLIST_FOREACH(dcl, &s->listeners, next) {
1705         if (con != (dcl->con ? dcl->con : active_console)) {
1706             continue;
1707         }
1708         if (dcl->ops->dpy_text_update) {
1709             dcl->ops->dpy_text_update(dcl, x, y, w, h);
1710         }
1711     }
1712 }
1713 
1714 void dpy_text_resize(QemuConsole *con, int w, int h)
1715 {
1716     DisplayState *s = con->ds;
1717     DisplayChangeListener *dcl;
1718 
1719     if (!qemu_console_is_visible(con)) {
1720         return;
1721     }
1722     QLIST_FOREACH(dcl, &s->listeners, next) {
1723         if (con != (dcl->con ? dcl->con : active_console)) {
1724             continue;
1725         }
1726         if (dcl->ops->dpy_text_resize) {
1727             dcl->ops->dpy_text_resize(dcl, w, h);
1728         }
1729     }
1730 }
1731 
1732 void dpy_mouse_set(QemuConsole *con, int x, int y, int on)
1733 {
1734     DisplayState *s = con->ds;
1735     DisplayChangeListener *dcl;
1736 
1737     if (!qemu_console_is_visible(con)) {
1738         return;
1739     }
1740     QLIST_FOREACH(dcl, &s->listeners, next) {
1741         if (con != (dcl->con ? dcl->con : active_console)) {
1742             continue;
1743         }
1744         if (dcl->ops->dpy_mouse_set) {
1745             dcl->ops->dpy_mouse_set(dcl, x, y, on);
1746         }
1747     }
1748 }
1749 
1750 void dpy_cursor_define(QemuConsole *con, QEMUCursor *cursor)
1751 {
1752     DisplayState *s = con->ds;
1753     DisplayChangeListener *dcl;
1754 
1755     if (!qemu_console_is_visible(con)) {
1756         return;
1757     }
1758     QLIST_FOREACH(dcl, &s->listeners, next) {
1759         if (con != (dcl->con ? dcl->con : active_console)) {
1760             continue;
1761         }
1762         if (dcl->ops->dpy_cursor_define) {
1763             dcl->ops->dpy_cursor_define(dcl, cursor);
1764         }
1765     }
1766 }
1767 
1768 bool dpy_cursor_define_supported(QemuConsole *con)
1769 {
1770     DisplayState *s = con->ds;
1771     DisplayChangeListener *dcl;
1772 
1773     QLIST_FOREACH(dcl, &s->listeners, next) {
1774         if (dcl->ops->dpy_cursor_define) {
1775             return true;
1776         }
1777     }
1778     return false;
1779 }
1780 
1781 QEMUGLContext dpy_gl_ctx_create(QemuConsole *con,
1782                                 struct QEMUGLParams *qparams)
1783 {
1784     assert(con->gl);
1785     return con->gl->ops->dpy_gl_ctx_create(con->gl, qparams);
1786 }
1787 
1788 void dpy_gl_ctx_destroy(QemuConsole *con, QEMUGLContext ctx)
1789 {
1790     assert(con->gl);
1791     con->gl->ops->dpy_gl_ctx_destroy(con->gl, ctx);
1792 }
1793 
1794 int dpy_gl_ctx_make_current(QemuConsole *con, QEMUGLContext ctx)
1795 {
1796     assert(con->gl);
1797     return con->gl->ops->dpy_gl_ctx_make_current(con->gl, ctx);
1798 }
1799 
1800 void dpy_gl_scanout_disable(QemuConsole *con)
1801 {
1802     assert(con->gl);
1803     con->gl->ops->dpy_gl_scanout_disable(con->gl);
1804 }
1805 
1806 void dpy_gl_scanout_texture(QemuConsole *con,
1807                             uint32_t backing_id,
1808                             bool backing_y_0_top,
1809                             uint32_t backing_width,
1810                             uint32_t backing_height,
1811                             uint32_t x, uint32_t y,
1812                             uint32_t width, uint32_t height)
1813 {
1814     assert(con->gl);
1815     con->gl->ops->dpy_gl_scanout_texture(con->gl, backing_id,
1816                                          backing_y_0_top,
1817                                          backing_width, backing_height,
1818                                          x, y, width, height);
1819 }
1820 
1821 void dpy_gl_scanout_dmabuf(QemuConsole *con,
1822                            QemuDmaBuf *dmabuf)
1823 {
1824     assert(con->gl);
1825     con->gl->ops->dpy_gl_scanout_dmabuf(con->gl, dmabuf);
1826 }
1827 
1828 void dpy_gl_cursor_dmabuf(QemuConsole *con, QemuDmaBuf *dmabuf,
1829                           bool have_hot, uint32_t hot_x, uint32_t hot_y)
1830 {
1831     assert(con->gl);
1832 
1833     if (con->gl->ops->dpy_gl_cursor_dmabuf) {
1834         con->gl->ops->dpy_gl_cursor_dmabuf(con->gl, dmabuf,
1835                                            have_hot, hot_x, hot_y);
1836     }
1837 }
1838 
1839 void dpy_gl_cursor_position(QemuConsole *con,
1840                             uint32_t pos_x, uint32_t pos_y)
1841 {
1842     assert(con->gl);
1843 
1844     if (con->gl->ops->dpy_gl_cursor_position) {
1845         con->gl->ops->dpy_gl_cursor_position(con->gl, pos_x, pos_y);
1846     }
1847 }
1848 
1849 void dpy_gl_release_dmabuf(QemuConsole *con,
1850                           QemuDmaBuf *dmabuf)
1851 {
1852     assert(con->gl);
1853 
1854     if (con->gl->ops->dpy_gl_release_dmabuf) {
1855         con->gl->ops->dpy_gl_release_dmabuf(con->gl, dmabuf);
1856     }
1857 }
1858 
1859 void dpy_gl_update(QemuConsole *con,
1860                    uint32_t x, uint32_t y, uint32_t w, uint32_t h)
1861 {
1862     assert(con->gl);
1863     con->gl->ops->dpy_gl_update(con->gl, x, y, w, h);
1864 }
1865 
1866 /***********************************************************/
1867 /* register display */
1868 
1869 /* console.c internal use only */
1870 static DisplayState *get_alloc_displaystate(void)
1871 {
1872     if (!display_state) {
1873         display_state = g_new0(DisplayState, 1);
1874         cursor_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
1875                                     text_console_update_cursor, NULL);
1876     }
1877     return display_state;
1878 }
1879 
1880 /*
1881  * Called by main(), after creating QemuConsoles
1882  * and before initializing ui (sdl/vnc/...).
1883  */
1884 DisplayState *init_displaystate(void)
1885 {
1886     gchar *name;
1887     QemuConsole *con;
1888 
1889     get_alloc_displaystate();
1890     QTAILQ_FOREACH(con, &consoles, next) {
1891         if (con->console_type != GRAPHIC_CONSOLE &&
1892             con->ds == NULL) {
1893             text_console_do_init(con->chr, display_state);
1894         }
1895 
1896         /* Hook up into the qom tree here (not in new_console()), once
1897          * all QemuConsoles are created and the order / numbering
1898          * doesn't change any more */
1899         name = g_strdup_printf("console[%d]", con->index);
1900         object_property_add_child(container_get(object_get_root(), "/backend"),
1901                                   name, OBJECT(con));
1902         g_free(name);
1903     }
1904 
1905     return display_state;
1906 }
1907 
1908 void graphic_console_set_hwops(QemuConsole *con,
1909                                const GraphicHwOps *hw_ops,
1910                                void *opaque)
1911 {
1912     con->hw_ops = hw_ops;
1913     con->hw = opaque;
1914 }
1915 
1916 QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
1917                                   const GraphicHwOps *hw_ops,
1918                                   void *opaque)
1919 {
1920     static const char noinit[] =
1921         "Guest has not initialized the display (yet).";
1922     int width = 640;
1923     int height = 480;
1924     QemuConsole *s;
1925     DisplayState *ds;
1926     DisplaySurface *surface;
1927 
1928     ds = get_alloc_displaystate();
1929     s = qemu_console_lookup_unused();
1930     if (s) {
1931         trace_console_gfx_reuse(s->index);
1932         if (s->surface) {
1933             width = surface_width(s->surface);
1934             height = surface_height(s->surface);
1935         }
1936     } else {
1937         trace_console_gfx_new();
1938         s = new_console(ds, GRAPHIC_CONSOLE, head);
1939         s->ui_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
1940                                    dpy_set_ui_info_timer, s);
1941     }
1942     graphic_console_set_hwops(s, hw_ops, opaque);
1943     if (dev) {
1944         object_property_set_link(OBJECT(s), "device", OBJECT(dev),
1945                                  &error_abort);
1946     }
1947 
1948     surface = qemu_create_placeholder_surface(width, height, noinit);
1949     dpy_gfx_replace_surface(s, surface);
1950     return s;
1951 }
1952 
1953 static const GraphicHwOps unused_ops = {
1954     /* no callbacks */
1955 };
1956 
1957 void graphic_console_close(QemuConsole *con)
1958 {
1959     static const char unplugged[] =
1960         "Guest display has been unplugged";
1961     DisplaySurface *surface;
1962     int width = 640;
1963     int height = 480;
1964 
1965     if (con->surface) {
1966         width = surface_width(con->surface);
1967         height = surface_height(con->surface);
1968     }
1969 
1970     trace_console_gfx_close(con->index);
1971     object_property_set_link(OBJECT(con), "device", NULL, &error_abort);
1972     graphic_console_set_hwops(con, &unused_ops, NULL);
1973 
1974     if (con->gl) {
1975         dpy_gl_scanout_disable(con);
1976     }
1977     surface = qemu_create_placeholder_surface(width, height, unplugged);
1978     dpy_gfx_replace_surface(con, surface);
1979 }
1980 
1981 QemuConsole *qemu_console_lookup_by_index(unsigned int index)
1982 {
1983     QemuConsole *con;
1984 
1985     QTAILQ_FOREACH(con, &consoles, next) {
1986         if (con->index == index) {
1987             return con;
1988         }
1989     }
1990     return NULL;
1991 }
1992 
1993 QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head)
1994 {
1995     QemuConsole *con;
1996     Object *obj;
1997     uint32_t h;
1998 
1999     QTAILQ_FOREACH(con, &consoles, next) {
2000         obj = object_property_get_link(OBJECT(con),
2001                                        "device", &error_abort);
2002         if (DEVICE(obj) != dev) {
2003             continue;
2004         }
2005         h = object_property_get_uint(OBJECT(con),
2006                                      "head", &error_abort);
2007         if (h != head) {
2008             continue;
2009         }
2010         return con;
2011     }
2012     return NULL;
2013 }
2014 
2015 QemuConsole *qemu_console_lookup_by_device_name(const char *device_id,
2016                                                 uint32_t head, Error **errp)
2017 {
2018     DeviceState *dev;
2019     QemuConsole *con;
2020 
2021     dev = qdev_find_recursive(sysbus_get_default(), device_id);
2022     if (dev == NULL) {
2023         error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
2024                   "Device '%s' not found", device_id);
2025         return NULL;
2026     }
2027 
2028     con = qemu_console_lookup_by_device(dev, head);
2029     if (con == NULL) {
2030         error_setg(errp, "Device %s (head %d) is not bound to a QemuConsole",
2031                    device_id, head);
2032         return NULL;
2033     }
2034 
2035     return con;
2036 }
2037 
2038 QemuConsole *qemu_console_lookup_unused(void)
2039 {
2040     QemuConsole *con;
2041     Object *obj;
2042 
2043     QTAILQ_FOREACH(con, &consoles, next) {
2044         if (con->hw_ops != &unused_ops) {
2045             continue;
2046         }
2047         obj = object_property_get_link(OBJECT(con),
2048                                        "device", &error_abort);
2049         if (obj != NULL) {
2050             continue;
2051         }
2052         return con;
2053     }
2054     return NULL;
2055 }
2056 
2057 bool qemu_console_is_visible(QemuConsole *con)
2058 {
2059     return (con == active_console) || (con->dcls > 0);
2060 }
2061 
2062 bool qemu_console_is_graphic(QemuConsole *con)
2063 {
2064     if (con == NULL) {
2065         con = active_console;
2066     }
2067     return con && (con->console_type == GRAPHIC_CONSOLE);
2068 }
2069 
2070 bool qemu_console_is_fixedsize(QemuConsole *con)
2071 {
2072     if (con == NULL) {
2073         con = active_console;
2074     }
2075     return con && (con->console_type != TEXT_CONSOLE);
2076 }
2077 
2078 bool qemu_console_is_gl_blocked(QemuConsole *con)
2079 {
2080     assert(con != NULL);
2081     return con->gl_block;
2082 }
2083 
2084 char *qemu_console_get_label(QemuConsole *con)
2085 {
2086     if (con->console_type == GRAPHIC_CONSOLE) {
2087         if (con->device) {
2088             return g_strdup(object_get_typename(con->device));
2089         }
2090         return g_strdup("VGA");
2091     } else {
2092         if (con->chr && con->chr->label) {
2093             return g_strdup(con->chr->label);
2094         }
2095         return g_strdup_printf("vc%d", con->index);
2096     }
2097 }
2098 
2099 int qemu_console_get_index(QemuConsole *con)
2100 {
2101     if (con == NULL) {
2102         con = active_console;
2103     }
2104     return con ? con->index : -1;
2105 }
2106 
2107 uint32_t qemu_console_get_head(QemuConsole *con)
2108 {
2109     if (con == NULL) {
2110         con = active_console;
2111     }
2112     return con ? con->head : -1;
2113 }
2114 
2115 int qemu_console_get_width(QemuConsole *con, int fallback)
2116 {
2117     if (con == NULL) {
2118         con = active_console;
2119     }
2120     return con ? surface_width(con->surface) : fallback;
2121 }
2122 
2123 int qemu_console_get_height(QemuConsole *con, int fallback)
2124 {
2125     if (con == NULL) {
2126         con = active_console;
2127     }
2128     return con ? surface_height(con->surface) : fallback;
2129 }
2130 
2131 static void vc_chr_accept_input(Chardev *chr)
2132 {
2133     VCChardev *drv = VC_CHARDEV(chr);
2134     QemuConsole *s = drv->console;
2135 
2136     kbd_send_chars(s);
2137 }
2138 
2139 static void vc_chr_set_echo(Chardev *chr, bool echo)
2140 {
2141     VCChardev *drv = VC_CHARDEV(chr);
2142     QemuConsole *s = drv->console;
2143 
2144     s->echo = echo;
2145 }
2146 
2147 static void text_console_update_cursor_timer(void)
2148 {
2149     timer_mod(cursor_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME)
2150               + CONSOLE_CURSOR_PERIOD / 2);
2151 }
2152 
2153 static void text_console_update_cursor(void *opaque)
2154 {
2155     QemuConsole *s;
2156     int count = 0;
2157 
2158     cursor_visible_phase = !cursor_visible_phase;
2159 
2160     QTAILQ_FOREACH(s, &consoles, next) {
2161         if (qemu_console_is_graphic(s) ||
2162             !qemu_console_is_visible(s)) {
2163             continue;
2164         }
2165         count++;
2166         graphic_hw_invalidate(s);
2167     }
2168 
2169     if (count) {
2170         text_console_update_cursor_timer();
2171     }
2172 }
2173 
2174 static const GraphicHwOps text_console_ops = {
2175     .invalidate  = text_console_invalidate,
2176     .text_update = text_console_update,
2177 };
2178 
2179 static void text_console_do_init(Chardev *chr, DisplayState *ds)
2180 {
2181     VCChardev *drv = VC_CHARDEV(chr);
2182     QemuConsole *s = drv->console;
2183     int g_width = 80 * FONT_WIDTH;
2184     int g_height = 24 * FONT_HEIGHT;
2185 
2186     fifo8_create(&s->out_fifo, 16);
2187     s->ds = ds;
2188 
2189     s->y_displayed = 0;
2190     s->y_base = 0;
2191     s->total_height = DEFAULT_BACKSCROLL;
2192     s->x = 0;
2193     s->y = 0;
2194     if (!s->surface) {
2195         if (active_console && active_console->surface) {
2196             g_width = surface_width(active_console->surface);
2197             g_height = surface_height(active_console->surface);
2198         }
2199         s->surface = qemu_create_displaysurface(g_width, g_height);
2200     }
2201 
2202     s->hw_ops = &text_console_ops;
2203     s->hw = s;
2204 
2205     /* Set text attribute defaults */
2206     s->t_attrib_default.bold = 0;
2207     s->t_attrib_default.uline = 0;
2208     s->t_attrib_default.blink = 0;
2209     s->t_attrib_default.invers = 0;
2210     s->t_attrib_default.unvisible = 0;
2211     s->t_attrib_default.fgcol = QEMU_COLOR_WHITE;
2212     s->t_attrib_default.bgcol = QEMU_COLOR_BLACK;
2213     /* set current text attributes to default */
2214     s->t_attrib = s->t_attrib_default;
2215     text_console_resize(s);
2216 
2217     if (chr->label) {
2218         char *msg;
2219 
2220         s->t_attrib.bgcol = QEMU_COLOR_BLUE;
2221         msg = g_strdup_printf("%s console\r\n", chr->label);
2222         vc_chr_write(chr, (uint8_t *)msg, strlen(msg));
2223         g_free(msg);
2224         s->t_attrib = s->t_attrib_default;
2225     }
2226 
2227     qemu_chr_be_event(chr, CHR_EVENT_OPENED);
2228 }
2229 
2230 static void vc_chr_open(Chardev *chr,
2231                         ChardevBackend *backend,
2232                         bool *be_opened,
2233                         Error **errp)
2234 {
2235     ChardevVC *vc = backend->u.vc.data;
2236     VCChardev *drv = VC_CHARDEV(chr);
2237     QemuConsole *s;
2238     unsigned width = 0;
2239     unsigned height = 0;
2240 
2241     if (vc->has_width) {
2242         width = vc->width;
2243     } else if (vc->has_cols) {
2244         width = vc->cols * FONT_WIDTH;
2245     }
2246 
2247     if (vc->has_height) {
2248         height = vc->height;
2249     } else if (vc->has_rows) {
2250         height = vc->rows * FONT_HEIGHT;
2251     }
2252 
2253     trace_console_txt_new(width, height);
2254     if (width == 0 || height == 0) {
2255         s = new_console(NULL, TEXT_CONSOLE, 0);
2256     } else {
2257         s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE, 0);
2258         s->surface = qemu_create_displaysurface(width, height);
2259     }
2260 
2261     if (!s) {
2262         error_setg(errp, "cannot create text console");
2263         return;
2264     }
2265 
2266     s->chr = chr;
2267     drv->console = s;
2268 
2269     if (display_state) {
2270         text_console_do_init(chr, display_state);
2271     }
2272 
2273     /* console/chardev init sometimes completes elsewhere in a 2nd
2274      * stage, so defer OPENED events until they are fully initialized
2275      */
2276     *be_opened = false;
2277 }
2278 
2279 void qemu_console_resize(QemuConsole *s, int width, int height)
2280 {
2281     DisplaySurface *surface;
2282 
2283     assert(s->console_type == GRAPHIC_CONSOLE);
2284 
2285     if (s->surface && (s->surface->flags & QEMU_ALLOCATED_FLAG) &&
2286         pixman_image_get_width(s->surface->image) == width &&
2287         pixman_image_get_height(s->surface->image) == height) {
2288         return;
2289     }
2290 
2291     surface = qemu_create_displaysurface(width, height);
2292     dpy_gfx_replace_surface(s, surface);
2293 }
2294 
2295 DisplaySurface *qemu_console_surface(QemuConsole *console)
2296 {
2297     return console->surface;
2298 }
2299 
2300 PixelFormat qemu_default_pixelformat(int bpp)
2301 {
2302     pixman_format_code_t fmt = qemu_default_pixman_format(bpp, true);
2303     PixelFormat pf = qemu_pixelformat_from_pixman(fmt);
2304     return pf;
2305 }
2306 
2307 static QemuDisplay *dpys[DISPLAY_TYPE__MAX];
2308 
2309 void qemu_display_register(QemuDisplay *ui)
2310 {
2311     assert(ui->type < DISPLAY_TYPE__MAX);
2312     dpys[ui->type] = ui;
2313 }
2314 
2315 bool qemu_display_find_default(DisplayOptions *opts)
2316 {
2317     static DisplayType prio[] = {
2318 #if defined(CONFIG_GTK)
2319         DISPLAY_TYPE_GTK,
2320 #endif
2321 #if defined(CONFIG_SDL)
2322         DISPLAY_TYPE_SDL,
2323 #endif
2324 #if defined(CONFIG_COCOA)
2325         DISPLAY_TYPE_COCOA
2326 #endif
2327     };
2328     int i;
2329 
2330     for (i = 0; i < (int)ARRAY_SIZE(prio); i++) {
2331         if (dpys[prio[i]] == NULL) {
2332             ui_module_load_one(DisplayType_str(prio[i]));
2333         }
2334         if (dpys[prio[i]] == NULL) {
2335             continue;
2336         }
2337         opts->type = prio[i];
2338         return true;
2339     }
2340     return false;
2341 }
2342 
2343 void qemu_display_early_init(DisplayOptions *opts)
2344 {
2345     assert(opts->type < DISPLAY_TYPE__MAX);
2346     if (opts->type == DISPLAY_TYPE_NONE) {
2347         return;
2348     }
2349     if (dpys[opts->type] == NULL) {
2350         ui_module_load_one(DisplayType_str(opts->type));
2351     }
2352     if (dpys[opts->type] == NULL) {
2353         error_report("Display '%s' is not available.",
2354                      DisplayType_str(opts->type));
2355         exit(1);
2356     }
2357     if (dpys[opts->type]->early_init) {
2358         dpys[opts->type]->early_init(opts);
2359     }
2360 }
2361 
2362 void qemu_display_init(DisplayState *ds, DisplayOptions *opts)
2363 {
2364     assert(opts->type < DISPLAY_TYPE__MAX);
2365     if (opts->type == DISPLAY_TYPE_NONE) {
2366         return;
2367     }
2368     assert(dpys[opts->type] != NULL);
2369     dpys[opts->type]->init(ds, opts);
2370 }
2371 
2372 void qemu_display_help(void)
2373 {
2374     int idx;
2375 
2376     printf("Available display backend types:\n");
2377     printf("none\n");
2378     for (idx = DISPLAY_TYPE_NONE; idx < DISPLAY_TYPE__MAX; idx++) {
2379         if (!dpys[idx]) {
2380             ui_module_load_one(DisplayType_str(idx));
2381         }
2382         if (dpys[idx]) {
2383             printf("%s\n",  DisplayType_str(dpys[idx]->type));
2384         }
2385     }
2386 }
2387 
2388 void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend, Error **errp)
2389 {
2390     int val;
2391     ChardevVC *vc;
2392 
2393     backend->type = CHARDEV_BACKEND_KIND_VC;
2394     vc = backend->u.vc.data = g_new0(ChardevVC, 1);
2395     qemu_chr_parse_common(opts, qapi_ChardevVC_base(vc));
2396 
2397     val = qemu_opt_get_number(opts, "width", 0);
2398     if (val != 0) {
2399         vc->has_width = true;
2400         vc->width = val;
2401     }
2402 
2403     val = qemu_opt_get_number(opts, "height", 0);
2404     if (val != 0) {
2405         vc->has_height = true;
2406         vc->height = val;
2407     }
2408 
2409     val = qemu_opt_get_number(opts, "cols", 0);
2410     if (val != 0) {
2411         vc->has_cols = true;
2412         vc->cols = val;
2413     }
2414 
2415     val = qemu_opt_get_number(opts, "rows", 0);
2416     if (val != 0) {
2417         vc->has_rows = true;
2418         vc->rows = val;
2419     }
2420 }
2421 
2422 static const TypeInfo qemu_console_info = {
2423     .name = TYPE_QEMU_CONSOLE,
2424     .parent = TYPE_OBJECT,
2425     .instance_size = sizeof(QemuConsole),
2426     .class_size = sizeof(QemuConsoleClass),
2427 };
2428 
2429 static void char_vc_class_init(ObjectClass *oc, void *data)
2430 {
2431     ChardevClass *cc = CHARDEV_CLASS(oc);
2432 
2433     cc->parse = qemu_chr_parse_vc;
2434     cc->open = vc_chr_open;
2435     cc->chr_write = vc_chr_write;
2436     cc->chr_accept_input = vc_chr_accept_input;
2437     cc->chr_set_echo = vc_chr_set_echo;
2438 }
2439 
2440 static const TypeInfo char_vc_type_info = {
2441     .name = TYPE_CHARDEV_VC,
2442     .parent = TYPE_CHARDEV,
2443     .instance_size = sizeof(VCChardev),
2444     .class_init = char_vc_class_init,
2445 };
2446 
2447 void qemu_console_early_init(void)
2448 {
2449     /* set the default vc driver */
2450     if (!object_class_by_name(TYPE_CHARDEV_VC)) {
2451         type_register(&char_vc_type_info);
2452     }
2453 }
2454 
2455 static void register_types(void)
2456 {
2457     type_register_static(&qemu_console_info);
2458 }
2459 
2460 type_init(register_types);
2461