xref: /openbmc/qemu/ui/console.c (revision 966f2ec3)
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(consoles_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, consoles_head);
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 static void qemu_unmap_displaysurface_guestmem(pixman_image_t *image,
1389                                                void *unused)
1390 {
1391     void *data = pixman_image_get_data(image);
1392     uint32_t size = pixman_image_get_stride(image) *
1393         pixman_image_get_height(image);
1394     cpu_physical_memory_unmap(data, size, 0, 0);
1395 }
1396 
1397 DisplaySurface *qemu_create_displaysurface_guestmem(int width, int height,
1398                                                     pixman_format_code_t format,
1399                                                     int linesize, uint64_t addr)
1400 {
1401     DisplaySurface *surface;
1402     hwaddr size;
1403     void *data;
1404 
1405     if (linesize == 0) {
1406         linesize = width * PIXMAN_FORMAT_BPP(format) / 8;
1407     }
1408 
1409     size = (hwaddr)linesize * height;
1410     data = cpu_physical_memory_map(addr, &size, 0);
1411     if (size != (hwaddr)linesize * height) {
1412         cpu_physical_memory_unmap(data, size, 0, 0);
1413         return NULL;
1414     }
1415 
1416     surface = qemu_create_displaysurface_from
1417         (width, height, format, linesize, data);
1418     pixman_image_set_destroy_function
1419         (surface->image, qemu_unmap_displaysurface_guestmem, NULL);
1420 
1421     return surface;
1422 }
1423 
1424 DisplaySurface *qemu_create_message_surface(int w, int h,
1425                                             const char *msg)
1426 {
1427     DisplaySurface *surface = qemu_create_displaysurface(w, h);
1428     pixman_color_t bg = color_table_rgb[0][QEMU_COLOR_BLACK];
1429     pixman_color_t fg = color_table_rgb[0][QEMU_COLOR_WHITE];
1430     pixman_image_t *glyph;
1431     int len, x, y, i;
1432 
1433     len = strlen(msg);
1434     x = (w / FONT_WIDTH  - len) / 2;
1435     y = (h / FONT_HEIGHT - 1)   / 2;
1436     for (i = 0; i < len; i++) {
1437         glyph = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, msg[i]);
1438         qemu_pixman_glyph_render(glyph, surface->image, &fg, &bg,
1439                                  x+i, y, FONT_WIDTH, FONT_HEIGHT);
1440         qemu_pixman_image_unref(glyph);
1441     }
1442     return surface;
1443 }
1444 
1445 void qemu_free_displaysurface(DisplaySurface *surface)
1446 {
1447     if (surface == NULL) {
1448         return;
1449     }
1450     trace_displaysurface_free(surface);
1451     qemu_pixman_image_unref(surface->image);
1452     g_free(surface);
1453 }
1454 
1455 bool console_has_gl(QemuConsole *con)
1456 {
1457     return con->gl != NULL;
1458 }
1459 
1460 bool console_has_gl_dmabuf(QemuConsole *con)
1461 {
1462     return con->gl != NULL && con->gl->ops->dpy_gl_scanout_dmabuf != NULL;
1463 }
1464 
1465 void register_displaychangelistener(DisplayChangeListener *dcl)
1466 {
1467     static const char nodev[] =
1468         "This VM has no graphic display device.";
1469     static DisplaySurface *dummy;
1470     QemuConsole *con;
1471 
1472     assert(!dcl->ds);
1473 
1474     if (dcl->ops->dpy_gl_ctx_create) {
1475         /* display has opengl support */
1476         assert(dcl->con);
1477         if (dcl->con->gl) {
1478             fprintf(stderr, "can't register two opengl displays (%s, %s)\n",
1479                     dcl->ops->dpy_name, dcl->con->gl->ops->dpy_name);
1480             exit(1);
1481         }
1482         dcl->con->gl = dcl;
1483     }
1484 
1485     trace_displaychangelistener_register(dcl, dcl->ops->dpy_name);
1486     dcl->ds = get_alloc_displaystate();
1487     QLIST_INSERT_HEAD(&dcl->ds->listeners, dcl, next);
1488     gui_setup_refresh(dcl->ds);
1489     if (dcl->con) {
1490         dcl->con->dcls++;
1491         con = dcl->con;
1492     } else {
1493         con = active_console;
1494     }
1495     if (dcl->ops->dpy_gfx_switch) {
1496         if (con) {
1497             dcl->ops->dpy_gfx_switch(dcl, con->surface);
1498         } else {
1499             if (!dummy) {
1500                 dummy = qemu_create_message_surface(640, 480, nodev);
1501             }
1502             dcl->ops->dpy_gfx_switch(dcl, dummy);
1503         }
1504     }
1505     text_console_update_cursor(NULL);
1506 }
1507 
1508 void update_displaychangelistener(DisplayChangeListener *dcl,
1509                                   uint64_t interval)
1510 {
1511     DisplayState *ds = dcl->ds;
1512 
1513     dcl->update_interval = interval;
1514     if (!ds->refreshing && ds->update_interval > interval) {
1515         timer_mod(ds->gui_timer, ds->last_update + interval);
1516     }
1517 }
1518 
1519 void unregister_displaychangelistener(DisplayChangeListener *dcl)
1520 {
1521     DisplayState *ds = dcl->ds;
1522     trace_displaychangelistener_unregister(dcl, dcl->ops->dpy_name);
1523     if (dcl->con) {
1524         dcl->con->dcls--;
1525     }
1526     QLIST_REMOVE(dcl, next);
1527     dcl->ds = NULL;
1528     gui_setup_refresh(ds);
1529 }
1530 
1531 static void dpy_set_ui_info_timer(void *opaque)
1532 {
1533     QemuConsole *con = opaque;
1534 
1535     con->hw_ops->ui_info(con->hw, con->head, &con->ui_info);
1536 }
1537 
1538 bool dpy_ui_info_supported(QemuConsole *con)
1539 {
1540     return con->hw_ops->ui_info != NULL;
1541 }
1542 
1543 int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info)
1544 {
1545     assert(con != NULL);
1546 
1547     if (!dpy_ui_info_supported(con)) {
1548         return -1;
1549     }
1550     if (memcmp(&con->ui_info, info, sizeof(con->ui_info)) == 0) {
1551         /* nothing changed -- ignore */
1552         return 0;
1553     }
1554 
1555     /*
1556      * Typically we get a flood of these as the user resizes the window.
1557      * Wait until the dust has settled (one second without updates), then
1558      * go notify the guest.
1559      */
1560     con->ui_info = *info;
1561     timer_mod(con->ui_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
1562     return 0;
1563 }
1564 
1565 void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
1566 {
1567     DisplayState *s = con->ds;
1568     DisplayChangeListener *dcl;
1569     int width = w;
1570     int height = h;
1571 
1572     if (con->surface) {
1573         width = surface_width(con->surface);
1574         height = surface_height(con->surface);
1575     }
1576     x = MAX(x, 0);
1577     y = MAX(y, 0);
1578     x = MIN(x, width);
1579     y = MIN(y, height);
1580     w = MIN(w, width - x);
1581     h = MIN(h, height - y);
1582 
1583     if (!qemu_console_is_visible(con)) {
1584         return;
1585     }
1586     QLIST_FOREACH(dcl, &s->listeners, next) {
1587         if (con != (dcl->con ? dcl->con : active_console)) {
1588             continue;
1589         }
1590         if (dcl->ops->dpy_gfx_update) {
1591             dcl->ops->dpy_gfx_update(dcl, x, y, w, h);
1592         }
1593     }
1594 }
1595 
1596 void dpy_gfx_update_full(QemuConsole *con)
1597 {
1598     if (!con->surface) {
1599         return;
1600     }
1601     dpy_gfx_update(con, 0, 0,
1602                    surface_width(con->surface),
1603                    surface_height(con->surface));
1604 }
1605 
1606 void dpy_gfx_replace_surface(QemuConsole *con,
1607                              DisplaySurface *surface)
1608 {
1609     DisplayState *s = con->ds;
1610     DisplaySurface *old_surface = con->surface;
1611     DisplayChangeListener *dcl;
1612 
1613     assert(old_surface != surface || surface == NULL);
1614 
1615     con->surface = surface;
1616     QLIST_FOREACH(dcl, &s->listeners, next) {
1617         if (con != (dcl->con ? dcl->con : active_console)) {
1618             continue;
1619         }
1620         if (dcl->ops->dpy_gfx_switch) {
1621             dcl->ops->dpy_gfx_switch(dcl, surface);
1622         }
1623     }
1624     qemu_free_displaysurface(old_surface);
1625 }
1626 
1627 bool dpy_gfx_check_format(QemuConsole *con,
1628                           pixman_format_code_t format)
1629 {
1630     DisplayChangeListener *dcl;
1631     DisplayState *s = con->ds;
1632 
1633     QLIST_FOREACH(dcl, &s->listeners, next) {
1634         if (dcl->con && dcl->con != con) {
1635             /* dcl bound to another console -> skip */
1636             continue;
1637         }
1638         if (dcl->ops->dpy_gfx_check_format) {
1639             if (!dcl->ops->dpy_gfx_check_format(dcl, format)) {
1640                 return false;
1641             }
1642         } else {
1643             /* default is to whitelist native 32 bpp only */
1644             if (format != qemu_default_pixman_format(32, true)) {
1645                 return false;
1646             }
1647         }
1648     }
1649     return true;
1650 }
1651 
1652 static void dpy_refresh(DisplayState *s)
1653 {
1654     DisplayChangeListener *dcl;
1655 
1656     QLIST_FOREACH(dcl, &s->listeners, next) {
1657         if (dcl->ops->dpy_refresh) {
1658             dcl->ops->dpy_refresh(dcl);
1659         }
1660     }
1661 }
1662 
1663 void dpy_text_cursor(QemuConsole *con, int x, int y)
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_cursor) {
1676             dcl->ops->dpy_text_cursor(dcl, x, y);
1677         }
1678     }
1679 }
1680 
1681 void dpy_text_update(QemuConsole *con, int x, int y, int w, int h)
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_text_update) {
1694             dcl->ops->dpy_text_update(dcl, x, y, w, h);
1695         }
1696     }
1697 }
1698 
1699 void dpy_text_resize(QemuConsole *con, int w, int h)
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_text_resize) {
1712             dcl->ops->dpy_text_resize(dcl, w, h);
1713         }
1714     }
1715 }
1716 
1717 void dpy_mouse_set(QemuConsole *con, int x, int y, int on)
1718 {
1719     DisplayState *s = con->ds;
1720     DisplayChangeListener *dcl;
1721 
1722     if (!qemu_console_is_visible(con)) {
1723         return;
1724     }
1725     QLIST_FOREACH(dcl, &s->listeners, next) {
1726         if (con != (dcl->con ? dcl->con : active_console)) {
1727             continue;
1728         }
1729         if (dcl->ops->dpy_mouse_set) {
1730             dcl->ops->dpy_mouse_set(dcl, x, y, on);
1731         }
1732     }
1733 }
1734 
1735 void dpy_cursor_define(QemuConsole *con, QEMUCursor *cursor)
1736 {
1737     DisplayState *s = con->ds;
1738     DisplayChangeListener *dcl;
1739 
1740     if (!qemu_console_is_visible(con)) {
1741         return;
1742     }
1743     QLIST_FOREACH(dcl, &s->listeners, next) {
1744         if (con != (dcl->con ? dcl->con : active_console)) {
1745             continue;
1746         }
1747         if (dcl->ops->dpy_cursor_define) {
1748             dcl->ops->dpy_cursor_define(dcl, cursor);
1749         }
1750     }
1751 }
1752 
1753 bool dpy_cursor_define_supported(QemuConsole *con)
1754 {
1755     DisplayState *s = con->ds;
1756     DisplayChangeListener *dcl;
1757 
1758     QLIST_FOREACH(dcl, &s->listeners, next) {
1759         if (dcl->ops->dpy_cursor_define) {
1760             return true;
1761         }
1762     }
1763     return false;
1764 }
1765 
1766 QEMUGLContext dpy_gl_ctx_create(QemuConsole *con,
1767                                 struct QEMUGLParams *qparams)
1768 {
1769     assert(con->gl);
1770     return con->gl->ops->dpy_gl_ctx_create(con->gl, qparams);
1771 }
1772 
1773 void dpy_gl_ctx_destroy(QemuConsole *con, QEMUGLContext ctx)
1774 {
1775     assert(con->gl);
1776     con->gl->ops->dpy_gl_ctx_destroy(con->gl, ctx);
1777 }
1778 
1779 int dpy_gl_ctx_make_current(QemuConsole *con, QEMUGLContext ctx)
1780 {
1781     assert(con->gl);
1782     return con->gl->ops->dpy_gl_ctx_make_current(con->gl, ctx);
1783 }
1784 
1785 QEMUGLContext dpy_gl_ctx_get_current(QemuConsole *con)
1786 {
1787     assert(con->gl);
1788     return con->gl->ops->dpy_gl_ctx_get_current(con->gl);
1789 }
1790 
1791 void dpy_gl_scanout_disable(QemuConsole *con)
1792 {
1793     assert(con->gl);
1794     if (con->gl->ops->dpy_gl_scanout_disable) {
1795         con->gl->ops->dpy_gl_scanout_disable(con->gl);
1796     } else {
1797         con->gl->ops->dpy_gl_scanout_texture(con->gl, 0, false, 0, 0,
1798                                              0, 0, 0, 0);
1799     }
1800 }
1801 
1802 void dpy_gl_scanout_texture(QemuConsole *con,
1803                             uint32_t backing_id,
1804                             bool backing_y_0_top,
1805                             uint32_t backing_width,
1806                             uint32_t backing_height,
1807                             uint32_t x, uint32_t y,
1808                             uint32_t width, uint32_t height)
1809 {
1810     assert(con->gl);
1811     con->gl->ops->dpy_gl_scanout_texture(con->gl, backing_id,
1812                                          backing_y_0_top,
1813                                          backing_width, backing_height,
1814                                          x, y, width, height);
1815 }
1816 
1817 void dpy_gl_scanout_dmabuf(QemuConsole *con,
1818                            QemuDmaBuf *dmabuf)
1819 {
1820     assert(con->gl);
1821     con->gl->ops->dpy_gl_scanout_dmabuf(con->gl, dmabuf);
1822 }
1823 
1824 void dpy_gl_cursor_dmabuf(QemuConsole *con, QemuDmaBuf *dmabuf,
1825                           bool have_hot, uint32_t hot_x, uint32_t hot_y)
1826 {
1827     assert(con->gl);
1828 
1829     if (con->gl->ops->dpy_gl_cursor_dmabuf) {
1830         con->gl->ops->dpy_gl_cursor_dmabuf(con->gl, dmabuf,
1831                                            have_hot, hot_x, hot_y);
1832     }
1833 }
1834 
1835 void dpy_gl_cursor_position(QemuConsole *con,
1836                             uint32_t pos_x, uint32_t pos_y)
1837 {
1838     assert(con->gl);
1839 
1840     if (con->gl->ops->dpy_gl_cursor_position) {
1841         con->gl->ops->dpy_gl_cursor_position(con->gl, pos_x, pos_y);
1842     }
1843 }
1844 
1845 void dpy_gl_release_dmabuf(QemuConsole *con,
1846                           QemuDmaBuf *dmabuf)
1847 {
1848     assert(con->gl);
1849 
1850     if (con->gl->ops->dpy_gl_release_dmabuf) {
1851         con->gl->ops->dpy_gl_release_dmabuf(con->gl, dmabuf);
1852     }
1853 }
1854 
1855 void dpy_gl_update(QemuConsole *con,
1856                    uint32_t x, uint32_t y, uint32_t w, uint32_t h)
1857 {
1858     assert(con->gl);
1859     con->gl->ops->dpy_gl_update(con->gl, x, y, w, h);
1860 }
1861 
1862 /***********************************************************/
1863 /* register display */
1864 
1865 /* console.c internal use only */
1866 static DisplayState *get_alloc_displaystate(void)
1867 {
1868     if (!display_state) {
1869         display_state = g_new0(DisplayState, 1);
1870         cursor_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
1871                                     text_console_update_cursor, NULL);
1872     }
1873     return display_state;
1874 }
1875 
1876 /*
1877  * Called by main(), after creating QemuConsoles
1878  * and before initializing ui (sdl/vnc/...).
1879  */
1880 DisplayState *init_displaystate(void)
1881 {
1882     gchar *name;
1883     QemuConsole *con;
1884 
1885     get_alloc_displaystate();
1886     QTAILQ_FOREACH(con, &consoles, next) {
1887         if (con->console_type != GRAPHIC_CONSOLE &&
1888             con->ds == NULL) {
1889             text_console_do_init(con->chr, display_state);
1890         }
1891 
1892         /* Hook up into the qom tree here (not in new_console()), once
1893          * all QemuConsoles are created and the order / numbering
1894          * doesn't change any more */
1895         name = g_strdup_printf("console[%d]", con->index);
1896         object_property_add_child(container_get(object_get_root(), "/backend"),
1897                                   name, OBJECT(con), &error_abort);
1898         g_free(name);
1899     }
1900 
1901     return display_state;
1902 }
1903 
1904 void graphic_console_set_hwops(QemuConsole *con,
1905                                const GraphicHwOps *hw_ops,
1906                                void *opaque)
1907 {
1908     con->hw_ops = hw_ops;
1909     con->hw = opaque;
1910 }
1911 
1912 QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
1913                                   const GraphicHwOps *hw_ops,
1914                                   void *opaque)
1915 {
1916     static const char noinit[] =
1917         "Guest has not initialized the display (yet).";
1918     int width = 640;
1919     int height = 480;
1920     QemuConsole *s;
1921     DisplayState *ds;
1922     DisplaySurface *surface;
1923 
1924     ds = get_alloc_displaystate();
1925     s = qemu_console_lookup_unused();
1926     if (s) {
1927         trace_console_gfx_reuse(s->index);
1928         if (s->surface) {
1929             width = surface_width(s->surface);
1930             height = surface_height(s->surface);
1931         }
1932     } else {
1933         trace_console_gfx_new();
1934         s = new_console(ds, GRAPHIC_CONSOLE, head);
1935         s->ui_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
1936                                    dpy_set_ui_info_timer, s);
1937     }
1938     graphic_console_set_hwops(s, hw_ops, opaque);
1939     if (dev) {
1940         object_property_set_link(OBJECT(s), OBJECT(dev), "device",
1941                                  &error_abort);
1942     }
1943 
1944     surface = qemu_create_message_surface(width, height, noinit);
1945     dpy_gfx_replace_surface(s, surface);
1946     return s;
1947 }
1948 
1949 static const GraphicHwOps unused_ops = {
1950     /* no callbacks */
1951 };
1952 
1953 void graphic_console_close(QemuConsole *con)
1954 {
1955     static const char unplugged[] =
1956         "Guest display has been unplugged";
1957     DisplaySurface *surface;
1958     int width = 640;
1959     int height = 480;
1960 
1961     if (con->surface) {
1962         width = surface_width(con->surface);
1963         height = surface_height(con->surface);
1964     }
1965 
1966     trace_console_gfx_close(con->index);
1967     object_property_set_link(OBJECT(con), NULL, "device", &error_abort);
1968     graphic_console_set_hwops(con, &unused_ops, NULL);
1969 
1970     if (con->gl) {
1971         dpy_gl_scanout_disable(con);
1972     }
1973     surface = qemu_create_message_surface(width, height, unplugged);
1974     dpy_gfx_replace_surface(con, surface);
1975 }
1976 
1977 QemuConsole *qemu_console_lookup_by_index(unsigned int index)
1978 {
1979     QemuConsole *con;
1980 
1981     QTAILQ_FOREACH(con, &consoles, next) {
1982         if (con->index == index) {
1983             return con;
1984         }
1985     }
1986     return NULL;
1987 }
1988 
1989 QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head)
1990 {
1991     QemuConsole *con;
1992     Object *obj;
1993     uint32_t h;
1994 
1995     QTAILQ_FOREACH(con, &consoles, next) {
1996         obj = object_property_get_link(OBJECT(con),
1997                                        "device", &error_abort);
1998         if (DEVICE(obj) != dev) {
1999             continue;
2000         }
2001         h = object_property_get_uint(OBJECT(con),
2002                                      "head", &error_abort);
2003         if (h != head) {
2004             continue;
2005         }
2006         return con;
2007     }
2008     return NULL;
2009 }
2010 
2011 QemuConsole *qemu_console_lookup_by_device_name(const char *device_id,
2012                                                 uint32_t head, Error **errp)
2013 {
2014     DeviceState *dev;
2015     QemuConsole *con;
2016 
2017     dev = qdev_find_recursive(sysbus_get_default(), device_id);
2018     if (dev == NULL) {
2019         error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
2020                   "Device '%s' not found", device_id);
2021         return NULL;
2022     }
2023 
2024     con = qemu_console_lookup_by_device(dev, head);
2025     if (con == NULL) {
2026         error_setg(errp, "Device %s (head %d) is not bound to a QemuConsole",
2027                    device_id, head);
2028         return NULL;
2029     }
2030 
2031     return con;
2032 }
2033 
2034 QemuConsole *qemu_console_lookup_unused(void)
2035 {
2036     QemuConsole *con;
2037     Object *obj;
2038 
2039     QTAILQ_FOREACH(con, &consoles, next) {
2040         if (con->hw_ops != &unused_ops) {
2041             continue;
2042         }
2043         obj = object_property_get_link(OBJECT(con),
2044                                        "device", &error_abort);
2045         if (obj != NULL) {
2046             continue;
2047         }
2048         return con;
2049     }
2050     return NULL;
2051 }
2052 
2053 bool qemu_console_is_visible(QemuConsole *con)
2054 {
2055     return (con == active_console) || (con->dcls > 0);
2056 }
2057 
2058 bool qemu_console_is_graphic(QemuConsole *con)
2059 {
2060     if (con == NULL) {
2061         con = active_console;
2062     }
2063     return con && (con->console_type == GRAPHIC_CONSOLE);
2064 }
2065 
2066 bool qemu_console_is_fixedsize(QemuConsole *con)
2067 {
2068     if (con == NULL) {
2069         con = active_console;
2070     }
2071     return con && (con->console_type != TEXT_CONSOLE);
2072 }
2073 
2074 bool qemu_console_is_gl_blocked(QemuConsole *con)
2075 {
2076     assert(con != NULL);
2077     return con->gl_block;
2078 }
2079 
2080 char *qemu_console_get_label(QemuConsole *con)
2081 {
2082     if (con->console_type == GRAPHIC_CONSOLE) {
2083         if (con->device) {
2084             return g_strdup(object_get_typename(con->device));
2085         }
2086         return g_strdup("VGA");
2087     } else {
2088         if (con->chr && con->chr->label) {
2089             return g_strdup(con->chr->label);
2090         }
2091         return g_strdup_printf("vc%d", con->index);
2092     }
2093 }
2094 
2095 int qemu_console_get_index(QemuConsole *con)
2096 {
2097     if (con == NULL) {
2098         con = active_console;
2099     }
2100     return con ? con->index : -1;
2101 }
2102 
2103 uint32_t qemu_console_get_head(QemuConsole *con)
2104 {
2105     if (con == NULL) {
2106         con = active_console;
2107     }
2108     return con ? con->head : -1;
2109 }
2110 
2111 QemuUIInfo *qemu_console_get_ui_info(QemuConsole *con)
2112 {
2113     assert(con != NULL);
2114     return &con->ui_info;
2115 }
2116 
2117 int qemu_console_get_width(QemuConsole *con, int fallback)
2118 {
2119     if (con == NULL) {
2120         con = active_console;
2121     }
2122     return con ? surface_width(con->surface) : fallback;
2123 }
2124 
2125 int qemu_console_get_height(QemuConsole *con, int fallback)
2126 {
2127     if (con == NULL) {
2128         con = active_console;
2129     }
2130     return con ? surface_height(con->surface) : fallback;
2131 }
2132 
2133 static void vc_chr_set_echo(Chardev *chr, bool echo)
2134 {
2135     VCChardev *drv = VC_CHARDEV(chr);
2136     QemuConsole *s = drv->console;
2137 
2138     s->echo = echo;
2139 }
2140 
2141 static void text_console_update_cursor_timer(void)
2142 {
2143     timer_mod(cursor_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME)
2144               + CONSOLE_CURSOR_PERIOD / 2);
2145 }
2146 
2147 static void text_console_update_cursor(void *opaque)
2148 {
2149     QemuConsole *s;
2150     int count = 0;
2151 
2152     cursor_visible_phase = !cursor_visible_phase;
2153 
2154     QTAILQ_FOREACH(s, &consoles, next) {
2155         if (qemu_console_is_graphic(s) ||
2156             !qemu_console_is_visible(s)) {
2157             continue;
2158         }
2159         count++;
2160         graphic_hw_invalidate(s);
2161     }
2162 
2163     if (count) {
2164         text_console_update_cursor_timer();
2165     }
2166 }
2167 
2168 static const GraphicHwOps text_console_ops = {
2169     .invalidate  = text_console_invalidate,
2170     .text_update = text_console_update,
2171 };
2172 
2173 static void text_console_do_init(Chardev *chr, DisplayState *ds)
2174 {
2175     VCChardev *drv = VC_CHARDEV(chr);
2176     QemuConsole *s = drv->console;
2177     int g_width = 80 * FONT_WIDTH;
2178     int g_height = 24 * FONT_HEIGHT;
2179 
2180     s->out_fifo.buf = s->out_fifo_buf;
2181     s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
2182     s->kbd_timer = timer_new_ms(QEMU_CLOCK_REALTIME, kbd_send_chars, s);
2183     s->ds = ds;
2184 
2185     s->y_displayed = 0;
2186     s->y_base = 0;
2187     s->total_height = DEFAULT_BACKSCROLL;
2188     s->x = 0;
2189     s->y = 0;
2190     if (!s->surface) {
2191         if (active_console && active_console->surface) {
2192             g_width = surface_width(active_console->surface);
2193             g_height = surface_height(active_console->surface);
2194         }
2195         s->surface = qemu_create_displaysurface(g_width, g_height);
2196     }
2197 
2198     s->hw_ops = &text_console_ops;
2199     s->hw = s;
2200 
2201     /* Set text attribute defaults */
2202     s->t_attrib_default.bold = 0;
2203     s->t_attrib_default.uline = 0;
2204     s->t_attrib_default.blink = 0;
2205     s->t_attrib_default.invers = 0;
2206     s->t_attrib_default.unvisible = 0;
2207     s->t_attrib_default.fgcol = QEMU_COLOR_WHITE;
2208     s->t_attrib_default.bgcol = QEMU_COLOR_BLACK;
2209     /* set current text attributes to default */
2210     s->t_attrib = s->t_attrib_default;
2211     text_console_resize(s);
2212 
2213     if (chr->label) {
2214         char msg[128];
2215         int len;
2216 
2217         s->t_attrib.bgcol = QEMU_COLOR_BLUE;
2218         len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
2219         vc_chr_write(chr, (uint8_t *)msg, len);
2220         s->t_attrib = s->t_attrib_default;
2221     }
2222 
2223     qemu_chr_be_event(chr, CHR_EVENT_OPENED);
2224 }
2225 
2226 static void vc_chr_open(Chardev *chr,
2227                         ChardevBackend *backend,
2228                         bool *be_opened,
2229                         Error **errp)
2230 {
2231     ChardevVC *vc = backend->u.vc.data;
2232     VCChardev *drv = VC_CHARDEV(chr);
2233     QemuConsole *s;
2234     unsigned width = 0;
2235     unsigned height = 0;
2236 
2237     if (vc->has_width) {
2238         width = vc->width;
2239     } else if (vc->has_cols) {
2240         width = vc->cols * FONT_WIDTH;
2241     }
2242 
2243     if (vc->has_height) {
2244         height = vc->height;
2245     } else if (vc->has_rows) {
2246         height = vc->rows * FONT_HEIGHT;
2247     }
2248 
2249     trace_console_txt_new(width, height);
2250     if (width == 0 || height == 0) {
2251         s = new_console(NULL, TEXT_CONSOLE, 0);
2252     } else {
2253         s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE, 0);
2254         s->surface = qemu_create_displaysurface(width, height);
2255     }
2256 
2257     if (!s) {
2258         error_setg(errp, "cannot create text console");
2259         return;
2260     }
2261 
2262     s->chr = chr;
2263     drv->console = s;
2264 
2265     if (display_state) {
2266         text_console_do_init(chr, display_state);
2267     }
2268 
2269     /* console/chardev init sometimes completes elsewhere in a 2nd
2270      * stage, so defer OPENED events until they are fully initialized
2271      */
2272     *be_opened = false;
2273 }
2274 
2275 void qemu_console_resize(QemuConsole *s, int width, int height)
2276 {
2277     DisplaySurface *surface;
2278 
2279     assert(s->console_type == GRAPHIC_CONSOLE);
2280 
2281     if (s->surface && (s->surface->flags & QEMU_ALLOCATED_FLAG) &&
2282         pixman_image_get_width(s->surface->image) == width &&
2283         pixman_image_get_height(s->surface->image) == height) {
2284         return;
2285     }
2286 
2287     surface = qemu_create_displaysurface(width, height);
2288     dpy_gfx_replace_surface(s, surface);
2289 }
2290 
2291 DisplaySurface *qemu_console_surface(QemuConsole *console)
2292 {
2293     return console->surface;
2294 }
2295 
2296 PixelFormat qemu_default_pixelformat(int bpp)
2297 {
2298     pixman_format_code_t fmt = qemu_default_pixman_format(bpp, true);
2299     PixelFormat pf = qemu_pixelformat_from_pixman(fmt);
2300     return pf;
2301 }
2302 
2303 static QemuDisplay *dpys[DISPLAY_TYPE__MAX];
2304 
2305 void qemu_display_register(QemuDisplay *ui)
2306 {
2307     assert(ui->type < DISPLAY_TYPE__MAX);
2308     dpys[ui->type] = ui;
2309 }
2310 
2311 bool qemu_display_find_default(DisplayOptions *opts)
2312 {
2313     static DisplayType prio[] = {
2314         DISPLAY_TYPE_GTK,
2315         DISPLAY_TYPE_SDL,
2316         DISPLAY_TYPE_COCOA
2317     };
2318     int i;
2319 
2320     for (i = 0; i < ARRAY_SIZE(prio); i++) {
2321         if (dpys[prio[i]] == NULL) {
2322             ui_module_load_one(DisplayType_str(prio[i]));
2323         }
2324         if (dpys[prio[i]] == NULL) {
2325             continue;
2326         }
2327         opts->type = prio[i];
2328         return true;
2329     }
2330     return false;
2331 }
2332 
2333 void qemu_display_early_init(DisplayOptions *opts)
2334 {
2335     assert(opts->type < DISPLAY_TYPE__MAX);
2336     if (opts->type == DISPLAY_TYPE_NONE) {
2337         return;
2338     }
2339     if (dpys[opts->type] == NULL) {
2340         ui_module_load_one(DisplayType_str(opts->type));
2341     }
2342     if (dpys[opts->type] == NULL) {
2343         error_report("Display '%s' is not available.",
2344                      DisplayType_str(opts->type));
2345         exit(1);
2346     }
2347     if (dpys[opts->type]->early_init) {
2348         dpys[opts->type]->early_init(opts);
2349     }
2350 }
2351 
2352 void qemu_display_init(DisplayState *ds, DisplayOptions *opts)
2353 {
2354     assert(opts->type < DISPLAY_TYPE__MAX);
2355     if (opts->type == DISPLAY_TYPE_NONE) {
2356         return;
2357     }
2358     assert(dpys[opts->type] != NULL);
2359     dpys[opts->type]->init(ds, opts);
2360 }
2361 
2362 void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend, Error **errp)
2363 {
2364     int val;
2365     ChardevVC *vc;
2366 
2367     backend->type = CHARDEV_BACKEND_KIND_VC;
2368     vc = backend->u.vc.data = g_new0(ChardevVC, 1);
2369     qemu_chr_parse_common(opts, qapi_ChardevVC_base(vc));
2370 
2371     val = qemu_opt_get_number(opts, "width", 0);
2372     if (val != 0) {
2373         vc->has_width = true;
2374         vc->width = val;
2375     }
2376 
2377     val = qemu_opt_get_number(opts, "height", 0);
2378     if (val != 0) {
2379         vc->has_height = true;
2380         vc->height = val;
2381     }
2382 
2383     val = qemu_opt_get_number(opts, "cols", 0);
2384     if (val != 0) {
2385         vc->has_cols = true;
2386         vc->cols = val;
2387     }
2388 
2389     val = qemu_opt_get_number(opts, "rows", 0);
2390     if (val != 0) {
2391         vc->has_rows = true;
2392         vc->rows = val;
2393     }
2394 }
2395 
2396 static const TypeInfo qemu_console_info = {
2397     .name = TYPE_QEMU_CONSOLE,
2398     .parent = TYPE_OBJECT,
2399     .instance_size = sizeof(QemuConsole),
2400     .class_size = sizeof(QemuConsoleClass),
2401 };
2402 
2403 static void char_vc_class_init(ObjectClass *oc, void *data)
2404 {
2405     ChardevClass *cc = CHARDEV_CLASS(oc);
2406 
2407     cc->parse = qemu_chr_parse_vc;
2408     cc->open = vc_chr_open;
2409     cc->chr_write = vc_chr_write;
2410     cc->chr_set_echo = vc_chr_set_echo;
2411 }
2412 
2413 static const TypeInfo char_vc_type_info = {
2414     .name = TYPE_CHARDEV_VC,
2415     .parent = TYPE_CHARDEV,
2416     .instance_size = sizeof(VCChardev),
2417     .class_init = char_vc_class_init,
2418 };
2419 
2420 void qemu_console_early_init(void)
2421 {
2422     /* set the default vc driver */
2423     if (!object_class_by_name(TYPE_CHARDEV_VC)) {
2424         type_register(&char_vc_type_info);
2425     }
2426 }
2427 
2428 static void register_types(void)
2429 {
2430     type_register_static(&qemu_console_info);
2431 }
2432 
2433 type_init(register_types);
2434