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