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