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