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