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