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