qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PULL 00/14] Ui patches
@ 2023-09-12 10:46 marcandre.lureau
  2023-09-12 10:46 ` [PULL 01/14] docs: vhost-user-gpu: add protocol changes for dmabuf modifiers marcandre.lureau
                   ` (13 more replies)
  0 siblings, 14 replies; 20+ messages in thread
From: marcandre.lureau @ 2023-09-12 10:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

The following changes since commit 9ef497755afc252fb8e060c9ea6b0987abfd20b6:

  Merge tag 'pull-vfio-20230911' of https://github.com/legoater/qemu into staging (2023-09-11 09:13:08 -0400)

are available in the Git repository at:

  https://gitlab.com/marcandre.lureau/qemu.git tags/ui-pull-request

for you to fetch changes up to a92e7bb4cad57cc5c8817fb18fb25650507b69f8:

  ui: add precondition for dpy_get_ui_info() (2023-09-12 11:14:09 +0400)

----------------------------------------------------------------
UI patch queue

- vhost-user-gpu: support dmabuf modifiers
- fix VNC crash when there are no active_console
- cleanups and refactoring in ui/vc code

----------------------------------------------------------------

Erico Nunes (3):
  docs: vhost-user-gpu: add protocol changes for dmabuf modifiers
  contrib/vhost-user-gpu: add support for sending dmabuf modifiers
  vhost-user-gpu: support dmabuf modifiers

Marc-André Lureau (11):
  vmmouse: replace DPRINTF with tracing
  vmmouse: use explicit code
  ui/vc: remove kbd_put_keysym() and update function calls
  ui/vc: rename kbd_put to qemu_text_console functions
  ui/console: remove redundant format field
  ui/vc: preliminary QemuTextConsole changes before split
  ui/vc: split off the VC part from console.c
  ui/console: move DisplaySurface to its own header
  virtio-gpu/win32: set the destroy function on load
  ui: fix crash when there are no active_console
  ui: add precondition for dpy_get_ui_info()

 docs/interop/vhost-user-gpu.rst         |   26 +-
 contrib/vhost-user-gpu/vugpu.h          |    9 +
 include/ui/console.h                    |   94 +-
 include/ui/surface.h                    |   95 ++
 ui/console-priv.h                       |   43 +
 contrib/vhost-user-gpu/vhost-user-gpu.c |    5 +-
 contrib/vhost-user-gpu/virgl.c          |   51 +-
 hw/display/vhost-user-gpu.c             |   17 +-
 hw/display/virtio-gpu.c                 |    4 +-
 hw/i386/vmmouse.c                       |   40 +-
 ui/console-gl.c                         |    2 +-
 ui/console-vc.c                         | 1079 ++++++++++++++++++++++
 ui/console.c                            | 1119 +----------------------
 ui/curses.c                             |    2 +-
 ui/gtk.c                                |    8 +-
 ui/sdl2-input.c                         |    4 +-
 ui/sdl2.c                               |    2 +-
 ui/spice-display.c                      |    2 +-
 ui/vnc.c                                |   56 +-
 hw/i386/trace-events                    |   10 +
 ui/cocoa.m                              |    2 +-
 ui/meson.build                          |    1 +
 22 files changed, 1426 insertions(+), 1245 deletions(-)
 create mode 100644 include/ui/surface.h
 create mode 100644 ui/console-priv.h
 create mode 100644 ui/console-vc.c

-- 
2.41.0



^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PULL 01/14] docs: vhost-user-gpu: add protocol changes for dmabuf modifiers
  2023-09-12 10:46 [PULL 00/14] Ui patches marcandre.lureau
@ 2023-09-12 10:46 ` marcandre.lureau
  2023-09-12 10:46 ` [PULL 02/14] contrib/vhost-user-gpu: add support for sending " marcandre.lureau
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: marcandre.lureau @ 2023-09-12 10:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Erico Nunes, Marc-André Lureau, Gerd Hoffmann

From: Erico Nunes <ernunes@redhat.com>

VHOST_USER_GPU_DMABUF_SCANOUT2 is defined as a message with all the
contents of VHOST_USER_GPU_DMABUF_SCANOUT plus the dmabuf modifiers
which were ommitted.

The VHOST_USER_GPU_PROTOCOL_F_DMABUF2 protocol feature is defined as a
way to check whether this new message is supported or not.

Signed-off-by: Erico Nunes <ernunes@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Sergio Lopez <slp@redhat.com>
Message-Id: <20230714153900.475857-2-ernunes@redhat.com>
---
 docs/interop/vhost-user-gpu.rst | 26 +++++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/docs/interop/vhost-user-gpu.rst b/docs/interop/vhost-user-gpu.rst
index b78806892d..3035822d05 100644
--- a/docs/interop/vhost-user-gpu.rst
+++ b/docs/interop/vhost-user-gpu.rst
@@ -134,6 +134,19 @@ VhostUserGpuEdidRequest
 :scanout-id: ``u32``, the scanout to get edid from
 
 
+VhostUserGpuDMABUFScanout2
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
++----------------+----------+
+| dmabuf_scanout | modifier |
++----------------+----------+
+
+:dmabuf_scanout: ``VhostUserGpuDMABUFScanout``, filled as described in the
+                 VhostUserGpuDMABUFScanout structure.
+
+:modifier: ``u64``, the DMABUF modifiers
+
+
 C structure
 -----------
 
@@ -163,7 +176,8 @@ Protocol features
 
 .. code:: c
 
-  #define VHOST_USER_GPU_PROTOCOL_F_EDID 0
+  #define VHOST_USER_GPU_PROTOCOL_F_EDID    0
+  #define VHOST_USER_GPU_PROTOCOL_F_DMABUF2 1
 
 New messages and communication changes are negotiated thanks to the
 ``VHOST_USER_GPU_GET_PROTOCOL_FEATURES`` and
@@ -263,3 +277,13 @@ Message types
   Retrieve the EDID data for a given scanout.
   This message requires the ``VHOST_USER_GPU_PROTOCOL_F_EDID`` protocol
   feature to be supported.
+
+``VHOST_USER_GPU_DMABUF_SCANOUT2``
+  :id: 12
+  :request payload: ``VhostUserGpuDMABUFScanout2``
+  :reply payload: N/A
+
+  Same as VHOST_USER_GPU_DMABUF_SCANOUT, but also sends the dmabuf modifiers
+  appended to the message, which were not provided in the other message.
+  This message requires the ``VHOST_USER_GPU_PROTOCOL_F_DMABUF2`` protocol
+  feature to be supported.
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PULL 02/14] contrib/vhost-user-gpu: add support for sending dmabuf modifiers
  2023-09-12 10:46 [PULL 00/14] Ui patches marcandre.lureau
  2023-09-12 10:46 ` [PULL 01/14] docs: vhost-user-gpu: add protocol changes for dmabuf modifiers marcandre.lureau
@ 2023-09-12 10:46 ` marcandre.lureau
  2023-09-12 10:46 ` [PULL 03/14] vhost-user-gpu: support " marcandre.lureau
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: marcandre.lureau @ 2023-09-12 10:46 UTC (permalink / raw)
  To: qemu-devel
  Cc: stefanha, Erico Nunes, Michael S. Tsirkin, Marc-André Lureau,
	Gerd Hoffmann

From: Erico Nunes <ernunes@redhat.com>

virglrenderer recently added virgl_renderer_resource_get_info_ext as a
new api, which gets resource information, including dmabuf modifiers.

We have to support dmabuf modifiers since the driver may choose to
allocate buffers with these modifiers for efficiency, and importing
buffers without modifiers information may result in completely broken
rendering.

Signed-off-by: Erico Nunes <ernunes@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Sergio Lopez <slp@redhat.com>
Message-Id: <20230714153900.475857-3-ernunes@redhat.com>
---
 contrib/vhost-user-gpu/vugpu.h          |  9 +++++
 contrib/vhost-user-gpu/vhost-user-gpu.c |  5 ++-
 contrib/vhost-user-gpu/virgl.c          | 51 +++++++++++++++++++++++--
 3 files changed, 61 insertions(+), 4 deletions(-)

diff --git a/contrib/vhost-user-gpu/vugpu.h b/contrib/vhost-user-gpu/vugpu.h
index f0f2069c47..509b679f03 100644
--- a/contrib/vhost-user-gpu/vugpu.h
+++ b/contrib/vhost-user-gpu/vugpu.h
@@ -37,6 +37,7 @@ typedef enum VhostUserGpuRequest {
     VHOST_USER_GPU_DMABUF_SCANOUT,
     VHOST_USER_GPU_DMABUF_UPDATE,
     VHOST_USER_GPU_GET_EDID,
+    VHOST_USER_GPU_DMABUF_SCANOUT2,
 } VhostUserGpuRequest;
 
 typedef struct VhostUserGpuDisplayInfoReply {
@@ -84,6 +85,11 @@ typedef struct VhostUserGpuDMABUFScanout {
     int fd_drm_fourcc;
 } QEMU_PACKED VhostUserGpuDMABUFScanout;
 
+typedef struct VhostUserGpuDMABUFScanout2 {
+    struct VhostUserGpuDMABUFScanout dmabuf_scanout;
+    uint64_t modifier;
+} QEMU_PACKED VhostUserGpuDMABUFScanout2;
+
 typedef struct VhostUserGpuEdidRequest {
     uint32_t scanout_id;
 } QEMU_PACKED VhostUserGpuEdidRequest;
@@ -98,6 +104,7 @@ typedef struct VhostUserGpuMsg {
         VhostUserGpuScanout scanout;
         VhostUserGpuUpdate update;
         VhostUserGpuDMABUFScanout dmabuf_scanout;
+        VhostUserGpuDMABUFScanout2 dmabuf_scanout2;
         VhostUserGpuEdidRequest edid_req;
         struct virtio_gpu_resp_edid resp_edid;
         struct virtio_gpu_resp_display_info display_info;
@@ -112,6 +119,7 @@ static VhostUserGpuMsg m __attribute__ ((unused));
 #define VHOST_USER_GPU_MSG_FLAG_REPLY 0x4
 
 #define VHOST_USER_GPU_PROTOCOL_F_EDID 0
+#define VHOST_USER_GPU_PROTOCOL_F_DMABUF2 1
 
 struct virtio_gpu_scanout {
     uint32_t width, height;
@@ -132,6 +140,7 @@ typedef struct VuGpu {
     bool virgl;
     bool virgl_inited;
     bool edid_inited;
+    bool use_modifiers;
     uint32_t inflight;
 
     struct virtio_gpu_scanout scanout[VIRTIO_GPU_MAX_SCANOUTS];
diff --git a/contrib/vhost-user-gpu/vhost-user-gpu.c b/contrib/vhost-user-gpu/vhost-user-gpu.c
index 2e7815a7a3..aa304475a0 100644
--- a/contrib/vhost-user-gpu/vhost-user-gpu.c
+++ b/contrib/vhost-user-gpu/vhost-user-gpu.c
@@ -1071,6 +1071,7 @@ static gboolean
 protocol_features_cb(gint fd, GIOCondition condition, gpointer user_data)
 {
     const uint64_t protocol_edid = (1 << VHOST_USER_GPU_PROTOCOL_F_EDID);
+    const uint64_t protocol_dmabuf2 = (1 << VHOST_USER_GPU_PROTOCOL_F_DMABUF2);
     VuGpu *g = user_data;
     uint64_t protocol_features;
     VhostUserGpuMsg msg = {
@@ -1082,7 +1083,7 @@ protocol_features_cb(gint fd, GIOCondition condition, gpointer user_data)
         return G_SOURCE_CONTINUE;
     }
 
-    protocol_features &= protocol_edid;
+    protocol_features &= (protocol_edid | protocol_dmabuf2);
 
     msg = (VhostUserGpuMsg) {
         .request = VHOST_USER_GPU_SET_PROTOCOL_FEATURES,
@@ -1100,6 +1101,8 @@ protocol_features_cb(gint fd, GIOCondition condition, gpointer user_data)
         exit(EXIT_FAILURE);
     }
 
+    g->use_modifiers = !!(protocol_features & protocol_dmabuf2);
+
     return G_SOURCE_REMOVE;
 }
 
diff --git a/contrib/vhost-user-gpu/virgl.c b/contrib/vhost-user-gpu/virgl.c
index 211aa110a9..1da6cc1588 100644
--- a/contrib/vhost-user-gpu/virgl.c
+++ b/contrib/vhost-user-gpu/virgl.c
@@ -318,6 +318,37 @@ virgl_resource_detach_backing(VuGpu *g,
     vg_cleanup_mapping_iov(g, res_iovs, num_iovs);
 }
 
+static int
+virgl_get_resource_info_modifiers(uint32_t resource_id,
+                                  struct virgl_renderer_resource_info *info,
+                                  uint64_t *modifiers)
+{
+    int ret;
+#ifdef VIRGL_RENDERER_RESOURCE_INFO_EXT_VERSION
+    struct virgl_renderer_resource_info_ext info_ext;
+    ret = virgl_renderer_resource_get_info_ext(resource_id, &info_ext);
+    if (ret < 0) {
+        return ret;
+    }
+
+    *info = info_ext.base;
+    *modifiers = info_ext.modifiers;
+#else
+    ret = virgl_renderer_resource_get_info(resource_id, info);
+    if (ret < 0) {
+        return ret;
+    }
+
+    /*
+     * Before virgl_renderer_resource_get_info_ext,
+     * getting the modifiers was not possible.
+     */
+    *modifiers = 0;
+#endif
+
+    return 0;
+}
+
 static void
 virgl_cmd_set_scanout(VuGpu *g,
                       struct virtio_gpu_ctrl_command *cmd)
@@ -338,7 +369,9 @@ virgl_cmd_set_scanout(VuGpu *g,
     memset(&info, 0, sizeof(info));
 
     if (ss.resource_id && ss.r.width && ss.r.height) {
-        ret = virgl_renderer_resource_get_info(ss.resource_id, &info);
+        uint64_t modifiers = 0;
+        ret = virgl_get_resource_info_modifiers(ss.resource_id, &info,
+                                                &modifiers);
         if (ret == -1) {
             g_critical("%s: illegal resource specified %d\n",
                        __func__, ss.resource_id);
@@ -354,8 +387,6 @@ virgl_cmd_set_scanout(VuGpu *g,
         }
         assert(fd >= 0);
         VhostUserGpuMsg msg = {
-            .request = VHOST_USER_GPU_DMABUF_SCANOUT,
-            .size = sizeof(VhostUserGpuDMABUFScanout),
             .payload.dmabuf_scanout.scanout_id = ss.scanout_id,
             .payload.dmabuf_scanout.x =  ss.r.x,
             .payload.dmabuf_scanout.y =  ss.r.y,
@@ -367,6 +398,20 @@ virgl_cmd_set_scanout(VuGpu *g,
             .payload.dmabuf_scanout.fd_flags = info.flags,
             .payload.dmabuf_scanout.fd_drm_fourcc = info.drm_fourcc
         };
+
+        if (g->use_modifiers) {
+            /*
+             * The mesage uses all the fields set in dmabuf_scanout plus
+             * modifiers which is appended after VhostUserGpuDMABUFScanout.
+             */
+            msg.request = VHOST_USER_GPU_DMABUF_SCANOUT2;
+            msg.size = sizeof(VhostUserGpuDMABUFScanout2);
+            msg.payload.dmabuf_scanout2.modifier = modifiers;
+        } else {
+            msg.request = VHOST_USER_GPU_DMABUF_SCANOUT;
+            msg.size = sizeof(VhostUserGpuDMABUFScanout);
+        }
+
         vg_send_msg(g, &msg, fd);
         close(fd);
     } else {
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PULL 03/14] vhost-user-gpu: support dmabuf modifiers
  2023-09-12 10:46 [PULL 00/14] Ui patches marcandre.lureau
  2023-09-12 10:46 ` [PULL 01/14] docs: vhost-user-gpu: add protocol changes for dmabuf modifiers marcandre.lureau
  2023-09-12 10:46 ` [PULL 02/14] contrib/vhost-user-gpu: add support for sending " marcandre.lureau
@ 2023-09-12 10:46 ` marcandre.lureau
  2023-09-12 10:46 ` [PULL 04/14] vmmouse: replace DPRINTF with tracing marcandre.lureau
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: marcandre.lureau @ 2023-09-12 10:46 UTC (permalink / raw)
  To: qemu-devel
  Cc: stefanha, Erico Nunes, Marc-André Lureau, Gerd Hoffmann,
	Michael S. Tsirkin

From: Erico Nunes <ernunes@redhat.com>

When the backend sends VHOST_USER_GPU_DMABUF_SCANOUT2, handle it
by getting the modifiers information which is now available.

Signed-off-by: Erico Nunes <ernunes@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Sergio Lopez <slp@redhat.com>
Message-Id: <20230714153900.475857-4-ernunes@redhat.com>
---
 hw/display/vhost-user-gpu.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c
index e8ee03094e..1150521d9d 100644
--- a/hw/display/vhost-user-gpu.c
+++ b/hw/display/vhost-user-gpu.c
@@ -32,6 +32,7 @@ typedef enum VhostUserGpuRequest {
     VHOST_USER_GPU_DMABUF_SCANOUT,
     VHOST_USER_GPU_DMABUF_UPDATE,
     VHOST_USER_GPU_GET_EDID,
+    VHOST_USER_GPU_DMABUF_SCANOUT2,
 } VhostUserGpuRequest;
 
 typedef struct VhostUserGpuDisplayInfoReply {
@@ -79,6 +80,11 @@ typedef struct VhostUserGpuDMABUFScanout {
     int fd_drm_fourcc;
 } QEMU_PACKED VhostUserGpuDMABUFScanout;
 
+typedef struct VhostUserGpuDMABUFScanout2 {
+    struct VhostUserGpuDMABUFScanout dmabuf_scanout;
+    uint64_t modifier;
+} QEMU_PACKED VhostUserGpuDMABUFScanout2;
+
 typedef struct VhostUserGpuEdidRequest {
     uint32_t scanout_id;
 } QEMU_PACKED VhostUserGpuEdidRequest;
@@ -93,6 +99,7 @@ typedef struct VhostUserGpuMsg {
         VhostUserGpuScanout scanout;
         VhostUserGpuUpdate update;
         VhostUserGpuDMABUFScanout dmabuf_scanout;
+        VhostUserGpuDMABUFScanout2 dmabuf_scanout2;
         VhostUserGpuEdidRequest edid_req;
         struct virtio_gpu_resp_edid resp_edid;
         struct virtio_gpu_resp_display_info display_info;
@@ -107,6 +114,7 @@ static VhostUserGpuMsg m __attribute__ ((unused));
 #define VHOST_USER_GPU_MSG_FLAG_REPLY 0x4
 
 #define VHOST_USER_GPU_PROTOCOL_F_EDID 0
+#define VHOST_USER_GPU_PROTOCOL_F_DMABUF2 1
 
 static void vhost_user_gpu_update_blocked(VhostUserGPU *g, bool blocked);
 
@@ -171,7 +179,8 @@ vhost_user_gpu_handle_display(VhostUserGPU *g, VhostUserGpuMsg *msg)
             .flags = VHOST_USER_GPU_MSG_FLAG_REPLY,
             .size = sizeof(uint64_t),
             .payload = {
-                .u64 = (1 << VHOST_USER_GPU_PROTOCOL_F_EDID)
+                .u64 = (1 << VHOST_USER_GPU_PROTOCOL_F_EDID) |
+                       (1 << VHOST_USER_GPU_PROTOCOL_F_DMABUF2)
             }
         };
 
@@ -236,6 +245,7 @@ vhost_user_gpu_handle_display(VhostUserGPU *g, VhostUserGpuMsg *msg)
 
         break;
     }
+    case VHOST_USER_GPU_DMABUF_SCANOUT2:
     case VHOST_USER_GPU_DMABUF_SCANOUT: {
         VhostUserGpuDMABUFScanout *m = &msg->payload.dmabuf_scanout;
         int fd = qemu_chr_fe_get_msgfd(&g->vhost_chr);
@@ -269,6 +279,11 @@ vhost_user_gpu_handle_display(VhostUserGPU *g, VhostUserGpuMsg *msg)
             .fourcc = m->fd_drm_fourcc,
             .y0_top = m->fd_flags & VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP,
         };
+        if (msg->request == VHOST_USER_GPU_DMABUF_SCANOUT2) {
+            VhostUserGpuDMABUFScanout2 *m2 = &msg->payload.dmabuf_scanout2;
+            dmabuf->modifier = m2->modifier;
+        }
+
         dpy_gl_scanout_dmabuf(con, dmabuf);
         break;
     }
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PULL 04/14] vmmouse: replace DPRINTF with tracing
  2023-09-12 10:46 [PULL 00/14] Ui patches marcandre.lureau
                   ` (2 preceding siblings ...)
  2023-09-12 10:46 ` [PULL 03/14] vhost-user-gpu: support " marcandre.lureau
@ 2023-09-12 10:46 ` marcandre.lureau
  2023-09-12 10:46 ` [PULL 05/14] vmmouse: use explicit code marcandre.lureau
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: marcandre.lureau @ 2023-09-12 10:46 UTC (permalink / raw)
  To: qemu-devel
  Cc: stefanha, Marc-André Lureau, Paolo Bonzini,
	Richard Henderson, Eduardo Habkost, Michael S. Tsirkin,
	Marcel Apfelbaum

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 hw/i386/vmmouse.c    | 29 ++++++++++++++---------------
 hw/i386/trace-events | 10 ++++++++++
 2 files changed, 24 insertions(+), 15 deletions(-)

diff --git a/hw/i386/vmmouse.c b/hw/i386/vmmouse.c
index 6cd624bd09..99b84a3817 100644
--- a/hw/i386/vmmouse.c
+++ b/hw/i386/vmmouse.c
@@ -32,6 +32,8 @@
 #include "cpu.h"
 #include "qom/object.h"
 
+#include "trace.h"
+
 /* debug only vmmouse */
 //#define DEBUG_VMMOUSE
 
@@ -50,12 +52,6 @@
 #define VMMOUSE_RIGHT_BUTTON       0x10
 #define VMMOUSE_MIDDLE_BUTTON      0x08
 
-#ifdef DEBUG_VMMOUSE
-#define DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
-#else
-#define DPRINTF(fmt, ...) do { } while (0)
-#endif
-
 #define TYPE_VMMOUSE "vmmouse"
 OBJECT_DECLARE_SIMPLE_TYPE(VMMouseState, VMMOUSE)
 
@@ -93,7 +89,8 @@ static void vmmouse_set_data(const uint32_t *data)
 
 static uint32_t vmmouse_get_status(VMMouseState *s)
 {
-    DPRINTF("vmmouse_get_status()\n");
+    trace_vmmouse_get_status();
+
     return (s->status << 16) | s->nb_queue;
 }
 
@@ -105,8 +102,7 @@ static void vmmouse_mouse_event(void *opaque, int x, int y, int dz, int buttons_
     if (s->nb_queue > (VMMOUSE_QUEUE_SIZE - 4))
         return;
 
-    DPRINTF("vmmouse_mouse_event(%d, %d, %d, %d)\n",
-            x, y, dz, buttons_state);
+    trace_vmmouse_mouse_event(x, y, dz, buttons_state);
 
     if ((buttons_state & MOUSE_EVENT_LBUTTON))
         buttons |= VMMOUSE_LEFT_BUTTON;
@@ -160,7 +156,7 @@ static void vmmouse_update_handler(VMMouseState *s, int absolute)
 
 static void vmmouse_read_id(VMMouseState *s)
 {
-    DPRINTF("vmmouse_read_id()\n");
+    trace_vmmouse_read_id();
 
     if (s->nb_queue == VMMOUSE_QUEUE_SIZE)
         return;
@@ -172,19 +168,22 @@ static void vmmouse_read_id(VMMouseState *s)
 
 static void vmmouse_request_relative(VMMouseState *s)
 {
-    DPRINTF("vmmouse_request_relative()\n");
+    trace_vmmouse_request_relative();
+
     vmmouse_update_handler(s, 0);
 }
 
 static void vmmouse_request_absolute(VMMouseState *s)
 {
-    DPRINTF("vmmouse_request_absolute()\n");
+    trace_vmmouse_request_absolute();
+
     vmmouse_update_handler(s, 1);
 }
 
 static void vmmouse_disable(VMMouseState *s)
 {
-    DPRINTF("vmmouse_disable()\n");
+    trace_vmmouse_disable();
+
     s->status = 0xffff;
     vmmouse_remove_handler(s);
 }
@@ -193,7 +192,7 @@ static void vmmouse_data(VMMouseState *s, uint32_t *data, uint32_t size)
 {
     int i;
 
-    DPRINTF("vmmouse_data(%d)\n", size);
+    trace_vmmouse_data(size);
 
     if (size == 0 || size > 6 || size > s->nb_queue) {
         printf("vmmouse: driver requested too much data %d\n", size);
@@ -293,7 +292,7 @@ static void vmmouse_realizefn(DeviceState *dev, Error **errp)
 {
     VMMouseState *s = VMMOUSE(dev);
 
-    DPRINTF("vmmouse_init\n");
+    trace_vmmouse_init();
 
     if (!s->i8042) {
         error_setg(errp, "'i8042' link is not set");
diff --git a/hw/i386/trace-events b/hw/i386/trace-events
index 04fd71bfc4..53c02d7ac8 100644
--- a/hw/i386/trace-events
+++ b/hw/i386/trace-events
@@ -121,3 +121,13 @@ x86_pic_interrupt(int irqn, int level) "PIC interrupt #%d level:%d"
 # port92.c
 port92_read(uint8_t val) "port92: read 0x%02x"
 port92_write(uint8_t val) "port92: write 0x%02x"
+
+# vmmouse.c
+vmmouse_get_status(void) ""
+vmmouse_mouse_event(int x, int y, int dz, int buttons_state) "event: x=%d y=%d dz=%d state=%d"
+vmmouse_init(void) ""
+vmmouse_read_id(void) ""
+vmmouse_request_relative(void) ""
+vmmouse_request_absolute(void) ""
+vmmouse_disable(void) ""
+vmmouse_data(uint32_t size) "data: size=%" PRIu32
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PULL 05/14] vmmouse: use explicit code
  2023-09-12 10:46 [PULL 00/14] Ui patches marcandre.lureau
                   ` (3 preceding siblings ...)
  2023-09-12 10:46 ` [PULL 04/14] vmmouse: replace DPRINTF with tracing marcandre.lureau
@ 2023-09-12 10:46 ` marcandre.lureau
  2023-09-12 10:46 ` [PULL 06/14] ui/vc: remove kbd_put_keysym() and update function calls marcandre.lureau
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: marcandre.lureau @ 2023-09-12 10:46 UTC (permalink / raw)
  To: qemu-devel
  Cc: stefanha, Marc-André Lureau, Michael S. Tsirkin,
	Marcel Apfelbaum, Paolo Bonzini, Richard Henderson,
	Eduardo Habkost

From: Marc-André Lureau <marcandre.lureau@redhat.com>

It's weird to shift x & y without obvious reason. Let's make this more
explicit and future-proof.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/i386/vmmouse.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/hw/i386/vmmouse.c b/hw/i386/vmmouse.c
index 99b84a3817..91320afa2f 100644
--- a/hw/i386/vmmouse.c
+++ b/hw/i386/vmmouse.c
@@ -52,6 +52,11 @@
 #define VMMOUSE_RIGHT_BUTTON       0x10
 #define VMMOUSE_MIDDLE_BUTTON      0x08
 
+#define VMMOUSE_MIN_X 0
+#define VMMOUSE_MIN_Y 0
+#define VMMOUSE_MAX_X 0xFFFF
+#define VMMOUSE_MAX_Y 0xFFFF
+
 #define TYPE_VMMOUSE "vmmouse"
 OBJECT_DECLARE_SIMPLE_TYPE(VMMouseState, VMMOUSE)
 
@@ -112,8 +117,12 @@ static void vmmouse_mouse_event(void *opaque, int x, int y, int dz, int buttons_
         buttons |= VMMOUSE_MIDDLE_BUTTON;
 
     if (s->absolute) {
-        x <<= 1;
-        y <<= 1;
+        x = qemu_input_scale_axis(x,
+                                  INPUT_EVENT_ABS_MIN, INPUT_EVENT_ABS_MAX,
+                                  VMMOUSE_MIN_X, VMMOUSE_MAX_X);
+        y = qemu_input_scale_axis(y,
+                                  INPUT_EVENT_ABS_MIN, INPUT_EVENT_ABS_MAX,
+                                  VMMOUSE_MIN_Y, VMMOUSE_MAX_Y);
     } else{
         /* add for guest vmmouse driver to judge this is a relative packet. */
         buttons |= VMMOUSE_RELATIVE_PACKET;
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PULL 06/14] ui/vc: remove kbd_put_keysym() and update function calls
  2023-09-12 10:46 [PULL 00/14] Ui patches marcandre.lureau
                   ` (4 preceding siblings ...)
  2023-09-12 10:46 ` [PULL 05/14] vmmouse: use explicit code marcandre.lureau
@ 2023-09-12 10:46 ` marcandre.lureau
  2023-09-12 10:46 ` [PULL 07/14] ui/vc: rename kbd_put to qemu_text_console functions marcandre.lureau
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: marcandre.lureau @ 2023-09-12 10:46 UTC (permalink / raw)
  To: qemu-devel
  Cc: stefanha, Marc-André Lureau, Gerd Hoffmann, Peter Maydell,
	Philippe Mathieu-Daudé, Akihiko Odaki

From: Marc-André Lureau <marcandre.lureau@redhat.com>

The function calls to `kbd_put_keysym` have been updated to now call
`kbd_put_keysym_console` with a NULL console parameter.

Like most console functions, NULL argument is now for the active console.

This will allow to rename the text console functions in a consistent manner.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 include/ui/console.h |  1 -
 ui/console.c         | 14 ++++++------
 ui/curses.c          |  2 +-
 ui/vnc.c             | 54 ++++++++++++++++++++++----------------------
 ui/cocoa.m           |  2 +-
 5 files changed, 36 insertions(+), 37 deletions(-)

diff --git a/include/ui/console.h b/include/ui/console.h
index 1ccd432b4d..9c362f0e87 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -115,7 +115,6 @@ bool qemu_mouse_set(int index, Error **errp);
 void kbd_put_keysym_console(QemuTextConsole *s, int keysym);
 bool kbd_put_qcode_console(QemuTextConsole *s, int qcode, bool ctrl);
 void kbd_put_string_console(QemuTextConsole *s, const char *str, int len);
-void kbd_put_keysym(int keysym);
 
 /* Touch devices */
 typedef struct touch_slot {
diff --git a/ui/console.c b/ui/console.c
index e4d61794bb..4c07791ac7 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1141,6 +1141,13 @@ void kbd_put_keysym_console(QemuTextConsole *s, int keysym)
     int c;
     uint32_t num_free;
 
+    if (!s) {
+        if (!QEMU_IS_TEXT_CONSOLE(active_console)) {
+            return;
+        }
+        s = QEMU_TEXT_CONSOLE(active_console);
+    }
+
     switch(keysym) {
     case QEMU_KEY_CTRL_UP:
         console_scroll(s, -1);
@@ -1231,13 +1238,6 @@ void kbd_put_string_console(QemuTextConsole *s, const char *str, int len)
     }
 }
 
-void kbd_put_keysym(int keysym)
-{
-    if (QEMU_IS_TEXT_CONSOLE(active_console)) {
-        kbd_put_keysym_console(QEMU_TEXT_CONSOLE(active_console), keysym);
-    }
-}
-
 static void text_console_invalidate(void *opaque)
 {
     QemuTextConsole *s = QEMU_TEXT_CONSOLE(opaque);
diff --git a/ui/curses.c b/ui/curses.c
index de962faa7c..4ddbbae7cd 100644
--- a/ui/curses.c
+++ b/ui/curses.c
@@ -400,7 +400,7 @@ static void curses_refresh(DisplayChangeListener *dcl)
             if (keysym == -1)
                 keysym = chr;
 
-            kbd_put_keysym(keysym);
+            kbd_put_keysym_console(NULL, keysym);
         }
     }
 }
diff --git a/ui/vnc.c b/ui/vnc.c
index 92964dcc0c..1fa4456744 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -1945,88 +1945,88 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
             case 0xb8:                          /* Right ALT */
                 break;
             case 0xc8:
-                kbd_put_keysym(QEMU_KEY_UP);
+                kbd_put_keysym_console(NULL, QEMU_KEY_UP);
                 break;
             case 0xd0:
-                kbd_put_keysym(QEMU_KEY_DOWN);
+                kbd_put_keysym_console(NULL, QEMU_KEY_DOWN);
                 break;
             case 0xcb:
-                kbd_put_keysym(QEMU_KEY_LEFT);
+                kbd_put_keysym_console(NULL, QEMU_KEY_LEFT);
                 break;
             case 0xcd:
-                kbd_put_keysym(QEMU_KEY_RIGHT);
+                kbd_put_keysym_console(NULL, QEMU_KEY_RIGHT);
                 break;
             case 0xd3:
-                kbd_put_keysym(QEMU_KEY_DELETE);
+                kbd_put_keysym_console(NULL, QEMU_KEY_DELETE);
                 break;
             case 0xc7:
-                kbd_put_keysym(QEMU_KEY_HOME);
+                kbd_put_keysym_console(NULL, QEMU_KEY_HOME);
                 break;
             case 0xcf:
-                kbd_put_keysym(QEMU_KEY_END);
+                kbd_put_keysym_console(NULL, QEMU_KEY_END);
                 break;
             case 0xc9:
-                kbd_put_keysym(QEMU_KEY_PAGEUP);
+                kbd_put_keysym_console(NULL, QEMU_KEY_PAGEUP);
                 break;
             case 0xd1:
-                kbd_put_keysym(QEMU_KEY_PAGEDOWN);
+                kbd_put_keysym_console(NULL, QEMU_KEY_PAGEDOWN);
                 break;
 
             case 0x47:
-                kbd_put_keysym(numlock ? '7' : QEMU_KEY_HOME);
+                kbd_put_keysym_console(NULL, numlock ? '7' : QEMU_KEY_HOME);
                 break;
             case 0x48:
-                kbd_put_keysym(numlock ? '8' : QEMU_KEY_UP);
+                kbd_put_keysym_console(NULL, numlock ? '8' : QEMU_KEY_UP);
                 break;
             case 0x49:
-                kbd_put_keysym(numlock ? '9' : QEMU_KEY_PAGEUP);
+                kbd_put_keysym_console(NULL, numlock ? '9' : QEMU_KEY_PAGEUP);
                 break;
             case 0x4b:
-                kbd_put_keysym(numlock ? '4' : QEMU_KEY_LEFT);
+                kbd_put_keysym_console(NULL, numlock ? '4' : QEMU_KEY_LEFT);
                 break;
             case 0x4c:
-                kbd_put_keysym('5');
+                kbd_put_keysym_console(NULL, '5');
                 break;
             case 0x4d:
-                kbd_put_keysym(numlock ? '6' : QEMU_KEY_RIGHT);
+                kbd_put_keysym_console(NULL, numlock ? '6' : QEMU_KEY_RIGHT);
                 break;
             case 0x4f:
-                kbd_put_keysym(numlock ? '1' : QEMU_KEY_END);
+                kbd_put_keysym_console(NULL, numlock ? '1' : QEMU_KEY_END);
                 break;
             case 0x50:
-                kbd_put_keysym(numlock ? '2' : QEMU_KEY_DOWN);
+                kbd_put_keysym_console(NULL, numlock ? '2' : QEMU_KEY_DOWN);
                 break;
             case 0x51:
-                kbd_put_keysym(numlock ? '3' : QEMU_KEY_PAGEDOWN);
+                kbd_put_keysym_console(NULL, numlock ? '3' : QEMU_KEY_PAGEDOWN);
                 break;
             case 0x52:
-                kbd_put_keysym('0');
+                kbd_put_keysym_console(NULL, '0');
                 break;
             case 0x53:
-                kbd_put_keysym(numlock ? '.' : QEMU_KEY_DELETE);
+                kbd_put_keysym_console(NULL, numlock ? '.' : QEMU_KEY_DELETE);
                 break;
 
             case 0xb5:
-                kbd_put_keysym('/');
+                kbd_put_keysym_console(NULL, '/');
                 break;
             case 0x37:
-                kbd_put_keysym('*');
+                kbd_put_keysym_console(NULL, '*');
                 break;
             case 0x4a:
-                kbd_put_keysym('-');
+                kbd_put_keysym_console(NULL, '-');
                 break;
             case 0x4e:
-                kbd_put_keysym('+');
+                kbd_put_keysym_console(NULL, '+');
                 break;
             case 0x9c:
-                kbd_put_keysym('\n');
+                kbd_put_keysym_console(NULL, '\n');
                 break;
 
             default:
                 if (control) {
-                    kbd_put_keysym(sym & 0x1f);
+                    kbd_put_keysym_console(NULL, sym & 0x1f);
                 } else {
-                    kbd_put_keysym(sym);
+                    kbd_put_keysym_console(NULL, sym);
                 }
                 break;
             }
diff --git a/ui/cocoa.m b/ui/cocoa.m
index 4d8989c4eb..90a89c5c8e 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -784,7 +784,7 @@ - (void) handleMonitorInput:(NSEvent *)event
     }
 
     if (keysym) {
-        kbd_put_keysym(keysym);
+        kbd_put_keysym_console(NULL, keysym);
     }
 }
 
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PULL 07/14] ui/vc: rename kbd_put to qemu_text_console functions
  2023-09-12 10:46 [PULL 00/14] Ui patches marcandre.lureau
                   ` (5 preceding siblings ...)
  2023-09-12 10:46 ` [PULL 06/14] ui/vc: remove kbd_put_keysym() and update function calls marcandre.lureau
@ 2023-09-12 10:46 ` marcandre.lureau
  2023-09-12 10:46 ` [PULL 08/14] ui/console: remove redundant format field marcandre.lureau
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: marcandre.lureau @ 2023-09-12 10:46 UTC (permalink / raw)
  To: qemu-devel
  Cc: stefanha, Marc-André Lureau, Gerd Hoffmann, Peter Maydell,
	Philippe Mathieu-Daudé, Akihiko Odaki

From: Marc-André Lureau <marcandre.lureau@redhat.com>

They are QemuTextConsole functions, let's make it clear.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
---
 include/ui/console.h |  6 ++---
 ui/console.c         | 10 ++++----
 ui/curses.c          |  2 +-
 ui/gtk.c             |  6 ++---
 ui/sdl2-input.c      |  4 ++--
 ui/sdl2.c            |  2 +-
 ui/vnc.c             | 54 ++++++++++++++++++++++----------------------
 ui/cocoa.m           |  2 +-
 8 files changed, 43 insertions(+), 43 deletions(-)

diff --git a/include/ui/console.h b/include/ui/console.h
index 9c362f0e87..26d63d17a2 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -112,9 +112,9 @@ bool qemu_mouse_set(int index, Error **errp);
 #define QEMU_KEY_CTRL_PAGEUP     0xe406
 #define QEMU_KEY_CTRL_PAGEDOWN   0xe407
 
-void kbd_put_keysym_console(QemuTextConsole *s, int keysym);
-bool kbd_put_qcode_console(QemuTextConsole *s, int qcode, bool ctrl);
-void kbd_put_string_console(QemuTextConsole *s, const char *str, int len);
+void qemu_text_console_put_keysym(QemuTextConsole *s, int keysym);
+bool qemu_text_console_put_qcode(QemuTextConsole *s, int qcode, bool ctrl);
+void qemu_text_console_put_string(QemuTextConsole *s, const char *str, int len);
 
 /* Touch devices */
 typedef struct touch_slot {
diff --git a/ui/console.c b/ui/console.c
index 4c07791ac7..7c60fc7d18 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1135,7 +1135,7 @@ static void kbd_send_chars(QemuTextConsole *s)
 }
 
 /* called when an ascii key is pressed */
-void kbd_put_keysym_console(QemuTextConsole *s, int keysym)
+void qemu_text_console_put_keysym(QemuTextConsole *s, int keysym)
 {
     uint8_t buf[16], *q;
     int c;
@@ -1217,7 +1217,7 @@ static const int ctrl_qcode_to_keysym[Q_KEY_CODE__MAX] = {
     [Q_KEY_CODE_PGDN]   = QEMU_KEY_CTRL_PAGEDOWN,
 };
 
-bool kbd_put_qcode_console(QemuTextConsole *s, int qcode, bool ctrl)
+bool qemu_text_console_put_qcode(QemuTextConsole *s, int qcode, bool ctrl)
 {
     int keysym;
 
@@ -1225,16 +1225,16 @@ bool kbd_put_qcode_console(QemuTextConsole *s, int qcode, bool ctrl)
     if (keysym == 0) {
         return false;
     }
-    kbd_put_keysym_console(s, keysym);
+    qemu_text_console_put_keysym(s, keysym);
     return true;
 }
 
-void kbd_put_string_console(QemuTextConsole *s, const char *str, int len)
+void qemu_text_console_put_string(QemuTextConsole *s, const char *str, int len)
 {
     int i;
 
     for (i = 0; i < len && str[i]; i++) {
-        kbd_put_keysym_console(s, str[i]);
+        qemu_text_console_put_keysym(s, str[i]);
     }
 }
 
diff --git a/ui/curses.c b/ui/curses.c
index 4ddbbae7cd..8bde8c5cf7 100644
--- a/ui/curses.c
+++ b/ui/curses.c
@@ -400,7 +400,7 @@ static void curses_refresh(DisplayChangeListener *dcl)
             if (keysym == -1)
                 keysym = chr;
 
-            kbd_put_keysym_console(NULL, keysym);
+            qemu_text_console_put_keysym(NULL, keysym);
         }
     }
 }
diff --git a/ui/gtk.c b/ui/gtk.c
index a14d56168d..c05f9a3f83 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -1190,12 +1190,12 @@ static gboolean gd_text_key_down(GtkWidget *widget,
     QemuTextConsole *con = QEMU_TEXT_CONSOLE(vc->gfx.dcl.con);
 
     if (key->keyval == GDK_KEY_Delete) {
-        kbd_put_qcode_console(con, Q_KEY_CODE_DELETE, false);
+        qemu_text_console_put_qcode(con, Q_KEY_CODE_DELETE, false);
     } else if (key->length) {
-        kbd_put_string_console(con, key->string, key->length);
+        qemu_text_console_put_string(con, key->string, key->length);
     } else {
         int qcode = gd_map_keycode(gd_get_keycode(key));
-        kbd_put_qcode_console(con, qcode, false);
+        qemu_text_console_put_qcode(con, qcode, false);
     }
     return TRUE;
 }
diff --git a/ui/sdl2-input.c b/ui/sdl2-input.c
index a318cc5867..b02a89ee7c 100644
--- a/ui/sdl2-input.c
+++ b/ui/sdl2-input.c
@@ -49,10 +49,10 @@ void sdl2_process_key(struct sdl2_console *scon,
         if (ev->type == SDL_KEYDOWN) {
             switch (qcode) {
             case Q_KEY_CODE_RET:
-                kbd_put_keysym_console(s, '\n');
+                qemu_text_console_put_keysym(s, '\n');
                 break;
             default:
-                kbd_put_qcode_console(s, qcode, ctrl);
+                qemu_text_console_put_qcode(s, qcode, ctrl);
                 break;
             }
         }
diff --git a/ui/sdl2.c b/ui/sdl2.c
index dfa260a507..178cc054ab 100644
--- a/ui/sdl2.c
+++ b/ui/sdl2.c
@@ -484,7 +484,7 @@ static void handle_textinput(SDL_Event *ev)
     }
 
     if (QEMU_IS_TEXT_CONSOLE(con)) {
-        kbd_put_string_console(QEMU_TEXT_CONSOLE(con), ev->text.text, strlen(ev->text.text));
+        qemu_text_console_put_string(QEMU_TEXT_CONSOLE(con), ev->text.text, strlen(ev->text.text));
     }
 }
 
diff --git a/ui/vnc.c b/ui/vnc.c
index 1fa4456744..22894b7b1f 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -1945,88 +1945,88 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
             case 0xb8:                          /* Right ALT */
                 break;
             case 0xc8:
-                kbd_put_keysym_console(NULL, QEMU_KEY_UP);
+                qemu_text_console_put_keysym(NULL, QEMU_KEY_UP);
                 break;
             case 0xd0:
-                kbd_put_keysym_console(NULL, QEMU_KEY_DOWN);
+                qemu_text_console_put_keysym(NULL, QEMU_KEY_DOWN);
                 break;
             case 0xcb:
-                kbd_put_keysym_console(NULL, QEMU_KEY_LEFT);
+                qemu_text_console_put_keysym(NULL, QEMU_KEY_LEFT);
                 break;
             case 0xcd:
-                kbd_put_keysym_console(NULL, QEMU_KEY_RIGHT);
+                qemu_text_console_put_keysym(NULL, QEMU_KEY_RIGHT);
                 break;
             case 0xd3:
-                kbd_put_keysym_console(NULL, QEMU_KEY_DELETE);
+                qemu_text_console_put_keysym(NULL, QEMU_KEY_DELETE);
                 break;
             case 0xc7:
-                kbd_put_keysym_console(NULL, QEMU_KEY_HOME);
+                qemu_text_console_put_keysym(NULL, QEMU_KEY_HOME);
                 break;
             case 0xcf:
-                kbd_put_keysym_console(NULL, QEMU_KEY_END);
+                qemu_text_console_put_keysym(NULL, QEMU_KEY_END);
                 break;
             case 0xc9:
-                kbd_put_keysym_console(NULL, QEMU_KEY_PAGEUP);
+                qemu_text_console_put_keysym(NULL, QEMU_KEY_PAGEUP);
                 break;
             case 0xd1:
-                kbd_put_keysym_console(NULL, QEMU_KEY_PAGEDOWN);
+                qemu_text_console_put_keysym(NULL, QEMU_KEY_PAGEDOWN);
                 break;
 
             case 0x47:
-                kbd_put_keysym_console(NULL, numlock ? '7' : QEMU_KEY_HOME);
+                qemu_text_console_put_keysym(NULL, numlock ? '7' : QEMU_KEY_HOME);
                 break;
             case 0x48:
-                kbd_put_keysym_console(NULL, numlock ? '8' : QEMU_KEY_UP);
+                qemu_text_console_put_keysym(NULL, numlock ? '8' : QEMU_KEY_UP);
                 break;
             case 0x49:
-                kbd_put_keysym_console(NULL, numlock ? '9' : QEMU_KEY_PAGEUP);
+                qemu_text_console_put_keysym(NULL, numlock ? '9' : QEMU_KEY_PAGEUP);
                 break;
             case 0x4b:
-                kbd_put_keysym_console(NULL, numlock ? '4' : QEMU_KEY_LEFT);
+                qemu_text_console_put_keysym(NULL, numlock ? '4' : QEMU_KEY_LEFT);
                 break;
             case 0x4c:
-                kbd_put_keysym_console(NULL, '5');
+                qemu_text_console_put_keysym(NULL, '5');
                 break;
             case 0x4d:
-                kbd_put_keysym_console(NULL, numlock ? '6' : QEMU_KEY_RIGHT);
+                qemu_text_console_put_keysym(NULL, numlock ? '6' : QEMU_KEY_RIGHT);
                 break;
             case 0x4f:
-                kbd_put_keysym_console(NULL, numlock ? '1' : QEMU_KEY_END);
+                qemu_text_console_put_keysym(NULL, numlock ? '1' : QEMU_KEY_END);
                 break;
             case 0x50:
-                kbd_put_keysym_console(NULL, numlock ? '2' : QEMU_KEY_DOWN);
+                qemu_text_console_put_keysym(NULL, numlock ? '2' : QEMU_KEY_DOWN);
                 break;
             case 0x51:
-                kbd_put_keysym_console(NULL, numlock ? '3' : QEMU_KEY_PAGEDOWN);
+                qemu_text_console_put_keysym(NULL, numlock ? '3' : QEMU_KEY_PAGEDOWN);
                 break;
             case 0x52:
-                kbd_put_keysym_console(NULL, '0');
+                qemu_text_console_put_keysym(NULL, '0');
                 break;
             case 0x53:
-                kbd_put_keysym_console(NULL, numlock ? '.' : QEMU_KEY_DELETE);
+                qemu_text_console_put_keysym(NULL, numlock ? '.' : QEMU_KEY_DELETE);
                 break;
 
             case 0xb5:
-                kbd_put_keysym_console(NULL, '/');
+                qemu_text_console_put_keysym(NULL, '/');
                 break;
             case 0x37:
-                kbd_put_keysym_console(NULL, '*');
+                qemu_text_console_put_keysym(NULL, '*');
                 break;
             case 0x4a:
-                kbd_put_keysym_console(NULL, '-');
+                qemu_text_console_put_keysym(NULL, '-');
                 break;
             case 0x4e:
-                kbd_put_keysym_console(NULL, '+');
+                qemu_text_console_put_keysym(NULL, '+');
                 break;
             case 0x9c:
-                kbd_put_keysym_console(NULL, '\n');
+                qemu_text_console_put_keysym(NULL, '\n');
                 break;
 
             default:
                 if (control) {
-                    kbd_put_keysym_console(NULL, sym & 0x1f);
+                    qemu_text_console_put_keysym(NULL, sym & 0x1f);
                 } else {
-                    kbd_put_keysym_console(NULL, sym);
+                    qemu_text_console_put_keysym(NULL, sym);
                 }
                 break;
             }
diff --git a/ui/cocoa.m b/ui/cocoa.m
index 90a89c5c8e..df6d13be38 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -784,7 +784,7 @@ - (void) handleMonitorInput:(NSEvent *)event
     }
 
     if (keysym) {
-        kbd_put_keysym_console(NULL, keysym);
+        qemu_text_console_put_keysym(NULL, keysym);
     }
 }
 
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PULL 08/14] ui/console: remove redundant format field
  2023-09-12 10:46 [PULL 00/14] Ui patches marcandre.lureau
                   ` (6 preceding siblings ...)
  2023-09-12 10:46 ` [PULL 07/14] ui/vc: rename kbd_put to qemu_text_console functions marcandre.lureau
@ 2023-09-12 10:46 ` marcandre.lureau
  2023-09-12 10:46 ` [PULL 09/14] ui/vc: preliminary QemuTextConsole changes before split marcandre.lureau
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: marcandre.lureau @ 2023-09-12 10:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Marc-André Lureau, Gerd Hoffmann

From: Marc-André Lureau <marcandre.lureau@redhat.com>

It's already part of PIXMAN image.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
---
 include/ui/console.h | 15 +++++++--------
 ui/console-gl.c      |  2 +-
 ui/console.c         |  4 +---
 ui/gtk.c             |  2 +-
 ui/spice-display.c   |  2 +-
 ui/vnc.c             |  2 +-
 6 files changed, 12 insertions(+), 15 deletions(-)

diff --git a/include/ui/console.h b/include/ui/console.h
index 26d63d17a2..93bb03a9e2 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -152,7 +152,6 @@ typedef struct ScanoutTexture {
 } ScanoutTexture;
 
 typedef struct DisplaySurface {
-    pixman_format_code_t format;
     pixman_image_t *image;
     uint8_t flags;
 #ifdef CONFIG_OPENGL
@@ -436,23 +435,23 @@ static inline int surface_height(DisplaySurface *s)
     return pixman_image_get_height(s->image);
 }
 
+static inline pixman_format_code_t surface_format(DisplaySurface *s)
+{
+    return pixman_image_get_format(s->image);
+}
+
 static inline int surface_bits_per_pixel(DisplaySurface *s)
 {
-    int bits = PIXMAN_FORMAT_BPP(s->format);
+    int bits = PIXMAN_FORMAT_BPP(surface_format(s));
     return bits;
 }
 
 static inline int surface_bytes_per_pixel(DisplaySurface *s)
 {
-    int bits = PIXMAN_FORMAT_BPP(s->format);
+    int bits = PIXMAN_FORMAT_BPP(surface_format(s));
     return DIV_ROUND_UP(bits, 8);
 }
 
-static inline pixman_format_code_t surface_format(DisplaySurface *s)
-{
-    return s->format;
-}
-
 typedef uint32_t console_ch_t;
 
 static inline void console_write_ch(console_ch_t *dest, uint32_t ch)
diff --git a/ui/console-gl.c b/ui/console-gl.c
index 8e3c9a3c8c..103b954017 100644
--- a/ui/console-gl.c
+++ b/ui/console-gl.c
@@ -53,7 +53,7 @@ void surface_gl_create_texture(QemuGLShader *gls,
         return;
     }
 
-    switch (surface->format) {
+    switch (surface_format(surface)) {
     case PIXMAN_BE_b8g8r8x8:
     case PIXMAN_BE_b8g8r8a8:
         surface->glformat = GL_BGRA_EXT;
diff --git a/ui/console.c b/ui/console.c
index 7c60fc7d18..4ff9f8b6e7 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1493,8 +1493,7 @@ DisplaySurface *qemu_create_displaysurface_from(int width, int height,
     DisplaySurface *surface = g_new0(DisplaySurface, 1);
 
     trace_displaysurface_create_from(surface, width, height, format);
-    surface->format = format;
-    surface->image = pixman_image_create_bits(surface->format,
+    surface->image = pixman_image_create_bits(format,
                                               width, height,
                                               (void *)data, linesize);
     assert(surface->image != NULL);
@@ -1511,7 +1510,6 @@ DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image)
     DisplaySurface *surface = g_new0(DisplaySurface, 1);
 
     trace_displaysurface_create_pixman(surface);
-    surface->format = pixman_image_get_format(image);
     surface->image = pixman_image_ref(image);
 
     return surface;
diff --git a/ui/gtk.c b/ui/gtk.c
index c05f9a3f83..e09f97a86b 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -514,7 +514,7 @@ static void gd_switch(DisplayChangeListener *dcl,
     }
     vc->gfx.ds = surface;
 
-    if (surface->format == PIXMAN_x8r8g8b8) {
+    if (surface_format(surface) == PIXMAN_x8r8g8b8) {
         /*
          * PIXMAN_x8r8g8b8 == CAIRO_FORMAT_RGB24
          *
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 0e2fbfb17c..5cc47bd668 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -437,7 +437,7 @@ void qemu_spice_display_switch(SimpleSpiceDisplay *ssd,
     }
     if (ssd->ds) {
         ssd->surface = pixman_image_ref(ssd->ds->image);
-        ssd->mirror  = qemu_pixman_mirror_create(ssd->ds->format,
+        ssd->mirror  = qemu_pixman_mirror_create(surface_format(ssd->ds),
                                                  ssd->ds->image);
         qemu_spice_create_host_primary(ssd);
     }
diff --git a/ui/vnc.c b/ui/vnc.c
index 22894b7b1f..6fd86996a5 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -833,7 +833,7 @@ static void vnc_dpy_switch(DisplayChangeListener *dcl,
     /* guest surface */
     qemu_pixman_image_unref(vd->guest.fb);
     vd->guest.fb = pixman_image_ref(surface->image);
-    vd->guest.format = surface->format;
+    vd->guest.format = surface_format(surface);
 
 
     if (pageflip) {
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PULL 09/14] ui/vc: preliminary QemuTextConsole changes before split
  2023-09-12 10:46 [PULL 00/14] Ui patches marcandre.lureau
                   ` (7 preceding siblings ...)
  2023-09-12 10:46 ` [PULL 08/14] ui/console: remove redundant format field marcandre.lureau
@ 2023-09-12 10:46 ` marcandre.lureau
  2023-09-12 10:46 ` [PULL 10/14] ui/vc: split off the VC part from console.c marcandre.lureau
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: marcandre.lureau @ 2023-09-12 10:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Marc-André Lureau, Gerd Hoffmann

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Those changes will help to split console.c unit in the following commit.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
---
 ui/console.c | 52 +++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 35 insertions(+), 17 deletions(-)

diff --git a/ui/console.c b/ui/console.c
index 4ff9f8b6e7..d9ac3717ff 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -174,7 +174,7 @@ static QEMUTimer *cursor_timer;
 
 static void dpy_refresh(DisplayState *s);
 static DisplayState *get_alloc_displaystate(void);
-static void text_console_update_cursor(void *opaque);
+static void qemu_text_console_update_cursor(void *opaque);
 static bool displaychangelistener_has_dmabuf(DisplayChangeListener *dcl);
 static bool console_compatible_with(QemuConsole *con,
                                     DisplayChangeListener *dcl, Error **errp);
@@ -1065,6 +1065,13 @@ static void displaychangelistener_display_console(DisplayChangeListener *dcl,
     }
 }
 
+static void
+qemu_text_console_select(QemuTextConsole *c)
+{
+    dpy_text_resize(QEMU_CONSOLE(c), c->width, c->height);
+    qemu_text_console_update_cursor(NULL);
+}
+
 void console_select(unsigned int index)
 {
     DisplayChangeListener *dcl;
@@ -1084,8 +1091,7 @@ void console_select(unsigned int index)
         }
 
         if (QEMU_IS_TEXT_CONSOLE(s)) {
-            dpy_text_resize(s, QEMU_TEXT_CONSOLE(s)->width, QEMU_TEXT_CONSOLE(s)->height);
-            text_console_update_cursor(NULL);
+            qemu_text_console_select(QEMU_TEXT_CONSOLE(s));
         }
     }
 }
@@ -1135,19 +1141,12 @@ static void kbd_send_chars(QemuTextConsole *s)
 }
 
 /* called when an ascii key is pressed */
-void qemu_text_console_put_keysym(QemuTextConsole *s, int keysym)
+static void qemu_text_console_handle_keysym(QemuTextConsole *s, int keysym)
 {
     uint8_t buf[16], *q;
     int c;
     uint32_t num_free;
 
-    if (!s) {
-        if (!QEMU_IS_TEXT_CONSOLE(active_console)) {
-            return;
-        }
-        s = QEMU_TEXT_CONSOLE(active_console);
-    }
-
     switch(keysym) {
     case QEMU_KEY_CTRL_UP:
         console_scroll(s, -1);
@@ -1192,6 +1191,18 @@ void qemu_text_console_put_keysym(QemuTextConsole *s, int keysym)
     }
 }
 
+void qemu_text_console_put_keysym(QemuTextConsole *s, int keysym)
+{
+    if (!s) {
+        if (!QEMU_IS_TEXT_CONSOLE(active_console)) {
+            return;
+        }
+        s = QEMU_TEXT_CONSOLE(active_console);
+    }
+
+    qemu_text_console_handle_keysym(s, keysym);
+}
+
 static const int qcode_to_keysym[Q_KEY_CODE__MAX] = {
     [Q_KEY_CODE_UP]     = QEMU_KEY_UP,
     [Q_KEY_CODE_DOWN]   = QEMU_KEY_DOWN,
@@ -1395,7 +1406,7 @@ qemu_text_console_class_init(ObjectClass *oc, void *data)
 {
     if (!cursor_timer) {
         cursor_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
-                                    text_console_update_cursor, NULL);
+                                    qemu_text_console_update_cursor, NULL);
     }
 }
 
@@ -1701,7 +1712,7 @@ void register_displaychangelistener(DisplayChangeListener *dcl)
     if (QEMU_IS_GRAPHIC_CONSOLE(con)) {
         dcl_set_graphic_cursor(dcl, QEMU_GRAPHIC_CONSOLE(con));
     }
-    text_console_update_cursor(NULL);
+    qemu_text_console_update_cursor(NULL);
 }
 
 void update_displaychangelistener(DisplayChangeListener *dcl,
@@ -2388,6 +2399,13 @@ bool qemu_console_is_multihead(DeviceState *dev)
     return false;
 }
 
+
+static const char *
+qemu_text_console_get_label(QemuTextConsole *c)
+{
+    return c->chr ? c->chr->label : NULL;
+}
+
 char *qemu_console_get_label(QemuConsole *con)
 {
     if (QEMU_IS_GRAPHIC_CONSOLE(con)) {
@@ -2411,9 +2429,9 @@ char *qemu_console_get_label(QemuConsole *con)
         }
         return g_strdup("VGA");
     } else if (QEMU_IS_TEXT_CONSOLE(con)) {
-        QemuTextConsole *c = QEMU_TEXT_CONSOLE(con);
-        if (c->chr && c->chr->label) {
-            return g_strdup(c->chr->label);
+        const char *label = qemu_text_console_get_label(QEMU_TEXT_CONSOLE(con));
+        if (label) {
+            return g_strdup(label);
         }
     }
 
@@ -2513,7 +2531,7 @@ int qemu_invalidate_text_consoles(void)
     return count;
 }
 
-static void text_console_update_cursor(void *opaque)
+static void qemu_text_console_update_cursor(void *opaque)
 {
     cursor_visible_phase = !cursor_visible_phase;
 
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PULL 10/14] ui/vc: split off the VC part from console.c
  2023-09-12 10:46 [PULL 00/14] Ui patches marcandre.lureau
                   ` (8 preceding siblings ...)
  2023-09-12 10:46 ` [PULL 09/14] ui/vc: preliminary QemuTextConsole changes before split marcandre.lureau
@ 2023-09-12 10:46 ` marcandre.lureau
  2023-09-12 10:46 ` [PULL 11/14] ui/console: move DisplaySurface to its own header marcandre.lureau
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: marcandre.lureau @ 2023-09-12 10:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Marc-André Lureau, Gerd Hoffmann

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Move common declarations to console-priv.h, and add a new unit
console-vc.c which will handle VC/chardev rendering, when pixman is
available.

(if necessary, the move could be done chunk by chunks)

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
---
 ui/console-priv.h |   43 ++
 ui/console-vc.c   | 1079 ++++++++++++++++++++++++++++++++++++++++++++
 ui/console.c      | 1096 +--------------------------------------------
 ui/meson.build    |    1 +
 4 files changed, 1126 insertions(+), 1093 deletions(-)
 create mode 100644 ui/console-priv.h
 create mode 100644 ui/console-vc.c

diff --git a/ui/console-priv.h b/ui/console-priv.h
new file mode 100644
index 0000000000..88569ed2cc
--- /dev/null
+++ b/ui/console-priv.h
@@ -0,0 +1,43 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * QEMU UI Console
+ */
+#ifndef CONSOLE_PRIV_H
+#define CONSOLE_PRIV_H
+
+#include "ui/console.h"
+#include "qemu/coroutine.h"
+#include "qemu/timer.h"
+
+#include "vgafont.h"
+
+#define FONT_HEIGHT 16
+#define FONT_WIDTH 8
+
+struct QemuConsole {
+    Object parent;
+
+    int index;
+    DisplayState *ds;
+    DisplaySurface *surface;
+    DisplayScanout scanout;
+    int dcls;
+    DisplayGLCtx *gl;
+    int gl_block;
+    QEMUTimer *gl_unblock_timer;
+    int window_id;
+    QemuUIInfo ui_info;
+    QEMUTimer *ui_timer;
+    const GraphicHwOps *hw_ops;
+    void *hw;
+    CoQueue dump_queue;
+
+    QTAILQ_ENTRY(QemuConsole) next;
+};
+
+void qemu_text_console_select(QemuTextConsole *c);
+const char * qemu_text_console_get_label(QemuTextConsole *c);
+void qemu_text_console_update_cursor(void);
+void qemu_text_console_handle_keysym(QemuTextConsole *s, int keysym);
+
+#endif
diff --git a/ui/console-vc.c b/ui/console-vc.c
new file mode 100644
index 0000000000..9c13cc2981
--- /dev/null
+++ b/ui/console-vc.c
@@ -0,0 +1,1079 @@
+/*
+ * SPDX-License-Identifier: MIT
+ * QEMU VC
+ */
+#include "qemu/osdep.h"
+
+#include "chardev/char.h"
+#include "qapi/error.h"
+#include "qemu/fifo8.h"
+#include "qemu/option.h"
+#include "ui/console.h"
+
+#include "trace.h"
+#include "console-priv.h"
+
+#define DEFAULT_BACKSCROLL 512
+#define CONSOLE_CURSOR_PERIOD 500
+
+typedef struct TextAttributes {
+    uint8_t fgcol:4;
+    uint8_t bgcol:4;
+    uint8_t bold:1;
+    uint8_t uline:1;
+    uint8_t blink:1;
+    uint8_t invers:1;
+    uint8_t unvisible:1;
+} TextAttributes;
+
+#define TEXT_ATTRIBUTES_DEFAULT ((TextAttributes) { \
+    .fgcol = QEMU_COLOR_WHITE,                      \
+    .bgcol = QEMU_COLOR_BLACK                       \
+})
+
+typedef struct TextCell {
+    uint8_t ch;
+    TextAttributes t_attrib;
+} TextCell;
+
+#define MAX_ESC_PARAMS 3
+
+enum TTYState {
+    TTY_STATE_NORM,
+    TTY_STATE_ESC,
+    TTY_STATE_CSI,
+};
+
+typedef struct QemuTextConsole {
+    QemuConsole parent;
+
+    int width;
+    int height;
+    int total_height;
+    int backscroll_height;
+    int x, y;
+    int y_displayed;
+    int y_base;
+    TextCell *cells;
+    int text_x[2], text_y[2], cursor_invalidate;
+    int echo;
+
+    int update_x0;
+    int update_y0;
+    int update_x1;
+    int update_y1;
+
+    Chardev *chr;
+    /* fifo for key pressed */
+    Fifo8 out_fifo;
+} QemuTextConsole;
+
+typedef QemuConsoleClass QemuTextConsoleClass;
+
+OBJECT_DEFINE_TYPE(QemuTextConsole, qemu_text_console, QEMU_TEXT_CONSOLE, QEMU_CONSOLE)
+
+typedef struct QemuFixedTextConsole {
+    QemuTextConsole parent;
+} QemuFixedTextConsole;
+
+typedef QemuTextConsoleClass QemuFixedTextConsoleClass;
+
+OBJECT_DEFINE_TYPE(QemuFixedTextConsole, qemu_fixed_text_console, QEMU_FIXED_TEXT_CONSOLE, QEMU_TEXT_CONSOLE)
+
+struct VCChardev {
+    Chardev parent;
+    QemuTextConsole *console;
+
+    enum TTYState state;
+    int esc_params[MAX_ESC_PARAMS];
+    int nb_esc_params;
+    TextAttributes t_attrib; /* currently active text attributes */
+    int x_saved, y_saved;
+};
+typedef struct VCChardev VCChardev;
+
+static const pixman_color_t color_table_rgb[2][8] = {
+    {   /* dark */
+        [QEMU_COLOR_BLACK]   = QEMU_PIXMAN_COLOR_BLACK,
+        [QEMU_COLOR_BLUE]    = QEMU_PIXMAN_COLOR(0x00, 0x00, 0xaa),  /* blue */
+        [QEMU_COLOR_GREEN]   = QEMU_PIXMAN_COLOR(0x00, 0xaa, 0x00),  /* green */
+        [QEMU_COLOR_CYAN]    = QEMU_PIXMAN_COLOR(0x00, 0xaa, 0xaa),  /* cyan */
+        [QEMU_COLOR_RED]     = QEMU_PIXMAN_COLOR(0xaa, 0x00, 0x00),  /* red */
+        [QEMU_COLOR_MAGENTA] = QEMU_PIXMAN_COLOR(0xaa, 0x00, 0xaa),  /* magenta */
+        [QEMU_COLOR_YELLOW]  = QEMU_PIXMAN_COLOR(0xaa, 0xaa, 0x00),  /* yellow */
+        [QEMU_COLOR_WHITE]   = QEMU_PIXMAN_COLOR_GRAY,
+    },
+    {   /* bright */
+        [QEMU_COLOR_BLACK]   = QEMU_PIXMAN_COLOR_BLACK,
+        [QEMU_COLOR_BLUE]    = QEMU_PIXMAN_COLOR(0x00, 0x00, 0xff),  /* blue */
+        [QEMU_COLOR_GREEN]   = QEMU_PIXMAN_COLOR(0x00, 0xff, 0x00),  /* green */
+        [QEMU_COLOR_CYAN]    = QEMU_PIXMAN_COLOR(0x00, 0xff, 0xff),  /* cyan */
+        [QEMU_COLOR_RED]     = QEMU_PIXMAN_COLOR(0xff, 0x00, 0x00),  /* red */
+        [QEMU_COLOR_MAGENTA] = QEMU_PIXMAN_COLOR(0xff, 0x00, 0xff),  /* magenta */
+        [QEMU_COLOR_YELLOW]  = QEMU_PIXMAN_COLOR(0xff, 0xff, 0x00),  /* yellow */
+        [QEMU_COLOR_WHITE]   = QEMU_PIXMAN_COLOR(0xff, 0xff, 0xff),  /* white */
+    }
+};
+
+static bool cursor_visible_phase;
+static QEMUTimer *cursor_timer;
+
+const char *
+qemu_text_console_get_label(QemuTextConsole *c)
+{
+    return c->chr ? c->chr->label : NULL;
+}
+
+static void qemu_console_fill_rect(QemuConsole *con, int posx, int posy,
+                                   int width, int height, pixman_color_t color)
+{
+    DisplaySurface *surface = qemu_console_surface(con);
+    pixman_rectangle16_t rect = {
+        .x = posx, .y = posy, .width = width, .height = height
+    };
+
+    assert(surface);
+    pixman_image_fill_rectangles(PIXMAN_OP_SRC, surface->image,
+                                 &color, 1, &rect);
+}
+
+/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
+static void qemu_console_bitblt(QemuConsole *con,
+                                int xs, int ys, int xd, int yd, int w, int h)
+{
+    DisplaySurface *surface = qemu_console_surface(con);
+
+    assert(surface);
+    pixman_image_composite(PIXMAN_OP_SRC,
+                           surface->image, NULL, surface->image,
+                           xs, ys, 0, 0, xd, yd, w, h);
+}
+
+static void vga_putcharxy(QemuConsole *s, int x, int y, int ch,
+                          TextAttributes *t_attrib)
+{
+    static pixman_image_t *glyphs[256];
+    DisplaySurface *surface = qemu_console_surface(s);
+    pixman_color_t fgcol, bgcol;
+
+    assert(surface);
+    if (t_attrib->invers) {
+        bgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
+        fgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
+    } else {
+        fgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
+        bgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
+    }
+
+    if (!glyphs[ch]) {
+        glyphs[ch] = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, ch);
+    }
+    qemu_pixman_glyph_render(glyphs[ch], surface->image,
+                             &fgcol, &bgcol, x, y, FONT_WIDTH, FONT_HEIGHT);
+}
+
+static void invalidate_xy(QemuTextConsole *s, int x, int y)
+{
+    if (!qemu_console_is_visible(QEMU_CONSOLE(s))) {
+        return;
+    }
+    if (s->update_x0 > x * FONT_WIDTH)
+        s->update_x0 = x * FONT_WIDTH;
+    if (s->update_y0 > y * FONT_HEIGHT)
+        s->update_y0 = y * FONT_HEIGHT;
+    if (s->update_x1 < (x + 1) * FONT_WIDTH)
+        s->update_x1 = (x + 1) * FONT_WIDTH;
+    if (s->update_y1 < (y + 1) * FONT_HEIGHT)
+        s->update_y1 = (y + 1) * FONT_HEIGHT;
+}
+
+static void console_show_cursor(QemuTextConsole *s, int show)
+{
+    TextCell *c;
+    int y, y1;
+    int x = s->x;
+
+    s->cursor_invalidate = 1;
+
+    if (x >= s->width) {
+        x = s->width - 1;
+    }
+    y1 = (s->y_base + s->y) % s->total_height;
+    y = y1 - s->y_displayed;
+    if (y < 0) {
+        y += s->total_height;
+    }
+    if (y < s->height) {
+        c = &s->cells[y1 * s->width + x];
+        if (show && cursor_visible_phase) {
+            TextAttributes t_attrib = TEXT_ATTRIBUTES_DEFAULT;
+            t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
+            vga_putcharxy(QEMU_CONSOLE(s), x, y, c->ch, &t_attrib);
+        } else {
+            vga_putcharxy(QEMU_CONSOLE(s), x, y, c->ch, &(c->t_attrib));
+        }
+        invalidate_xy(s, x, y);
+    }
+}
+
+static void console_refresh(QemuTextConsole *s)
+{
+    DisplaySurface *surface = qemu_console_surface(QEMU_CONSOLE(s));
+    TextCell *c;
+    int x, y, y1;
+
+    assert(surface);
+    s->text_x[0] = 0;
+    s->text_y[0] = 0;
+    s->text_x[1] = s->width - 1;
+    s->text_y[1] = s->height - 1;
+    s->cursor_invalidate = 1;
+
+    qemu_console_fill_rect(QEMU_CONSOLE(s), 0, 0, surface_width(surface), surface_height(surface),
+                           color_table_rgb[0][QEMU_COLOR_BLACK]);
+    y1 = s->y_displayed;
+    for (y = 0; y < s->height; y++) {
+        c = s->cells + y1 * s->width;
+        for (x = 0; x < s->width; x++) {
+            vga_putcharxy(QEMU_CONSOLE(s), x, y, c->ch,
+                          &(c->t_attrib));
+            c++;
+        }
+        if (++y1 == s->total_height) {
+            y1 = 0;
+        }
+    }
+    console_show_cursor(s, 1);
+    dpy_gfx_update(QEMU_CONSOLE(s), 0, 0,
+                   surface_width(surface), surface_height(surface));
+}
+
+static void console_scroll(QemuTextConsole *s, int ydelta)
+{
+    int i, y1;
+
+    if (ydelta > 0) {
+        for(i = 0; i < ydelta; i++) {
+            if (s->y_displayed == s->y_base)
+                break;
+            if (++s->y_displayed == s->total_height)
+                s->y_displayed = 0;
+        }
+    } else {
+        ydelta = -ydelta;
+        i = s->backscroll_height;
+        if (i > s->total_height - s->height)
+            i = s->total_height - s->height;
+        y1 = s->y_base - i;
+        if (y1 < 0)
+            y1 += s->total_height;
+        for(i = 0; i < ydelta; i++) {
+            if (s->y_displayed == y1)
+                break;
+            if (--s->y_displayed < 0)
+                s->y_displayed = s->total_height - 1;
+        }
+    }
+    console_refresh(s);
+}
+
+static void kbd_send_chars(QemuTextConsole *s)
+{
+    uint32_t len, avail;
+
+    len = qemu_chr_be_can_write(s->chr);
+    avail = fifo8_num_used(&s->out_fifo);
+    while (len > 0 && avail > 0) {
+        const uint8_t *buf;
+        uint32_t size;
+
+        buf = fifo8_pop_buf(&s->out_fifo, MIN(len, avail), &size);
+        qemu_chr_be_write(s->chr, buf, size);
+        len = qemu_chr_be_can_write(s->chr);
+        avail -= size;
+    }
+}
+
+/* called when an ascii key is pressed */
+void qemu_text_console_handle_keysym(QemuTextConsole *s, int keysym)
+{
+    uint8_t buf[16], *q;
+    int c;
+    uint32_t num_free;
+
+    switch(keysym) {
+    case QEMU_KEY_CTRL_UP:
+        console_scroll(s, -1);
+        break;
+    case QEMU_KEY_CTRL_DOWN:
+        console_scroll(s, 1);
+        break;
+    case QEMU_KEY_CTRL_PAGEUP:
+        console_scroll(s, -10);
+        break;
+    case QEMU_KEY_CTRL_PAGEDOWN:
+        console_scroll(s, 10);
+        break;
+    default:
+        /* convert the QEMU keysym to VT100 key string */
+        q = buf;
+        if (keysym >= 0xe100 && keysym <= 0xe11f) {
+            *q++ = '\033';
+            *q++ = '[';
+            c = keysym - 0xe100;
+            if (c >= 10)
+                *q++ = '0' + (c / 10);
+            *q++ = '0' + (c % 10);
+            *q++ = '~';
+        } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
+            *q++ = '\033';
+            *q++ = '[';
+            *q++ = keysym & 0xff;
+        } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
+            qemu_chr_write(s->chr, (uint8_t *)"\r", 1, true);
+            *q++ = '\n';
+        } else {
+            *q++ = keysym;
+        }
+        if (s->echo) {
+            qemu_chr_write(s->chr, buf, q - buf, true);
+        }
+        num_free = fifo8_num_free(&s->out_fifo);
+        fifo8_push_all(&s->out_fifo, buf, MIN(num_free, q - buf));
+        kbd_send_chars(s);
+        break;
+    }
+}
+
+static void text_console_update(void *opaque, console_ch_t *chardata)
+{
+    QemuTextConsole *s = QEMU_TEXT_CONSOLE(opaque);
+    int i, j, src;
+
+    if (s->text_x[0] <= s->text_x[1]) {
+        src = (s->y_base + s->text_y[0]) * s->width;
+        chardata += s->text_y[0] * s->width;
+        for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
+            for (j = 0; j < s->width; j++, src++) {
+                console_write_ch(chardata ++,
+                                 ATTR2CHTYPE(s->cells[src].ch,
+                                             s->cells[src].t_attrib.fgcol,
+                                             s->cells[src].t_attrib.bgcol,
+                                             s->cells[src].t_attrib.bold));
+            }
+        dpy_text_update(QEMU_CONSOLE(s), s->text_x[0], s->text_y[0],
+                        s->text_x[1] - s->text_x[0], i - s->text_y[0]);
+        s->text_x[0] = s->width;
+        s->text_y[0] = s->height;
+        s->text_x[1] = 0;
+        s->text_y[1] = 0;
+    }
+    if (s->cursor_invalidate) {
+        dpy_text_cursor(QEMU_CONSOLE(s), s->x, s->y);
+        s->cursor_invalidate = 0;
+    }
+}
+
+static void text_console_resize(QemuTextConsole *t)
+{
+    QemuConsole *s = QEMU_CONSOLE(t);
+    TextCell *cells, *c, *c1;
+    int w1, x, y, last_width, w, h;
+
+    assert(s->scanout.kind == SCANOUT_SURFACE);
+
+    w = surface_width(s->surface) / FONT_WIDTH;
+    h = surface_height(s->surface) / FONT_HEIGHT;
+    if (w == t->width && h == t->height) {
+        return;
+    }
+
+    last_width = t->width;
+    t->width = w;
+    t->height = h;
+
+    w1 = MIN(t->width, last_width);
+
+    cells = g_new(TextCell, t->width * t->total_height + 1);
+    for (y = 0; y < t->total_height; y++) {
+        c = &cells[y * t->width];
+        if (w1 > 0) {
+            c1 = &t->cells[y * last_width];
+            for (x = 0; x < w1; x++) {
+                *c++ = *c1++;
+            }
+        }
+        for (x = w1; x < t->width; x++) {
+            c->ch = ' ';
+            c->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
+            c++;
+        }
+    }
+    g_free(t->cells);
+    t->cells = cells;
+}
+
+static void vc_put_lf(VCChardev *vc)
+{
+    QemuTextConsole *s = vc->console;
+    TextCell *c;
+    int x, y1;
+
+    s->y++;
+    if (s->y >= s->height) {
+        s->y = s->height - 1;
+
+        if (s->y_displayed == s->y_base) {
+            if (++s->y_displayed == s->total_height)
+                s->y_displayed = 0;
+        }
+        if (++s->y_base == s->total_height)
+            s->y_base = 0;
+        if (s->backscroll_height < s->total_height)
+            s->backscroll_height++;
+        y1 = (s->y_base + s->height - 1) % s->total_height;
+        c = &s->cells[y1 * s->width];
+        for(x = 0; x < s->width; x++) {
+            c->ch = ' ';
+            c->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
+            c++;
+        }
+        if (s->y_displayed == s->y_base) {
+            s->text_x[0] = 0;
+            s->text_y[0] = 0;
+            s->text_x[1] = s->width - 1;
+            s->text_y[1] = s->height - 1;
+
+            qemu_console_bitblt(QEMU_CONSOLE(s), 0, FONT_HEIGHT, 0, 0,
+                                s->width * FONT_WIDTH,
+                                (s->height - 1) * FONT_HEIGHT);
+            qemu_console_fill_rect(QEMU_CONSOLE(s), 0, (s->height - 1) * FONT_HEIGHT,
+                                   s->width * FONT_WIDTH, FONT_HEIGHT,
+                                   color_table_rgb[0][TEXT_ATTRIBUTES_DEFAULT.bgcol]);
+            s->update_x0 = 0;
+            s->update_y0 = 0;
+            s->update_x1 = s->width * FONT_WIDTH;
+            s->update_y1 = s->height * FONT_HEIGHT;
+        }
+    }
+}
+
+/* Set console attributes depending on the current escape codes.
+ * NOTE: I know this code is not very efficient (checking every color for it
+ * self) but it is more readable and better maintainable.
+ */
+static void vc_handle_escape(VCChardev *vc)
+{
+    int i;
+
+    for (i = 0; i < vc->nb_esc_params; i++) {
+        switch (vc->esc_params[i]) {
+            case 0: /* reset all console attributes to default */
+                vc->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
+                break;
+            case 1:
+                vc->t_attrib.bold = 1;
+                break;
+            case 4:
+                vc->t_attrib.uline = 1;
+                break;
+            case 5:
+                vc->t_attrib.blink = 1;
+                break;
+            case 7:
+                vc->t_attrib.invers = 1;
+                break;
+            case 8:
+                vc->t_attrib.unvisible = 1;
+                break;
+            case 22:
+                vc->t_attrib.bold = 0;
+                break;
+            case 24:
+                vc->t_attrib.uline = 0;
+                break;
+            case 25:
+                vc->t_attrib.blink = 0;
+                break;
+            case 27:
+                vc->t_attrib.invers = 0;
+                break;
+            case 28:
+                vc->t_attrib.unvisible = 0;
+                break;
+            /* set foreground color */
+            case 30:
+                vc->t_attrib.fgcol = QEMU_COLOR_BLACK;
+                break;
+            case 31:
+                vc->t_attrib.fgcol = QEMU_COLOR_RED;
+                break;
+            case 32:
+                vc->t_attrib.fgcol = QEMU_COLOR_GREEN;
+                break;
+            case 33:
+                vc->t_attrib.fgcol = QEMU_COLOR_YELLOW;
+                break;
+            case 34:
+                vc->t_attrib.fgcol = QEMU_COLOR_BLUE;
+                break;
+            case 35:
+                vc->t_attrib.fgcol = QEMU_COLOR_MAGENTA;
+                break;
+            case 36:
+                vc->t_attrib.fgcol = QEMU_COLOR_CYAN;
+                break;
+            case 37:
+                vc->t_attrib.fgcol = QEMU_COLOR_WHITE;
+                break;
+            /* set background color */
+            case 40:
+                vc->t_attrib.bgcol = QEMU_COLOR_BLACK;
+                break;
+            case 41:
+                vc->t_attrib.bgcol = QEMU_COLOR_RED;
+                break;
+            case 42:
+                vc->t_attrib.bgcol = QEMU_COLOR_GREEN;
+                break;
+            case 43:
+                vc->t_attrib.bgcol = QEMU_COLOR_YELLOW;
+                break;
+            case 44:
+                vc->t_attrib.bgcol = QEMU_COLOR_BLUE;
+                break;
+            case 45:
+                vc->t_attrib.bgcol = QEMU_COLOR_MAGENTA;
+                break;
+            case 46:
+                vc->t_attrib.bgcol = QEMU_COLOR_CYAN;
+                break;
+            case 47:
+                vc->t_attrib.bgcol = QEMU_COLOR_WHITE;
+                break;
+        }
+    }
+}
+
+static void vc_update_xy(VCChardev *vc, int x, int y)
+{
+    QemuTextConsole *s = vc->console;
+    TextCell *c;
+    int y1, y2;
+
+    s->text_x[0] = MIN(s->text_x[0], x);
+    s->text_x[1] = MAX(s->text_x[1], x);
+    s->text_y[0] = MIN(s->text_y[0], y);
+    s->text_y[1] = MAX(s->text_y[1], y);
+
+    y1 = (s->y_base + y) % s->total_height;
+    y2 = y1 - s->y_displayed;
+    if (y2 < 0) {
+        y2 += s->total_height;
+    }
+    if (y2 < s->height) {
+        if (x >= s->width) {
+            x = s->width - 1;
+        }
+        c = &s->cells[y1 * s->width + x];
+        vga_putcharxy(QEMU_CONSOLE(s), x, y2, c->ch,
+                      &(c->t_attrib));
+        invalidate_xy(s, x, y2);
+    }
+}
+
+static void vc_clear_xy(VCChardev *vc, int x, int y)
+{
+    QemuTextConsole *s = vc->console;
+    int y1 = (s->y_base + y) % s->total_height;
+    if (x >= s->width) {
+        x = s->width - 1;
+    }
+    TextCell *c = &s->cells[y1 * s->width + x];
+    c->ch = ' ';
+    c->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
+    vc_update_xy(vc, x, y);
+}
+
+static void vc_put_one(VCChardev *vc, int ch)
+{
+    QemuTextConsole *s = vc->console;
+    TextCell *c;
+    int y1;
+    if (s->x >= s->width) {
+        /* line wrap */
+        s->x = 0;
+        vc_put_lf(vc);
+    }
+    y1 = (s->y_base + s->y) % s->total_height;
+    c = &s->cells[y1 * s->width + s->x];
+    c->ch = ch;
+    c->t_attrib = vc->t_attrib;
+    vc_update_xy(vc, s->x, s->y);
+    s->x++;
+}
+
+static void vc_respond_str(VCChardev *vc, const char *buf)
+{
+    while (*buf) {
+        vc_put_one(vc, *buf);
+        buf++;
+    }
+}
+
+/* set cursor, checking bounds */
+static void vc_set_cursor(VCChardev *vc, int x, int y)
+{
+    QemuTextConsole *s = vc->console;
+
+    if (x < 0) {
+        x = 0;
+    }
+    if (y < 0) {
+        y = 0;
+    }
+    if (y >= s->height) {
+        y = s->height - 1;
+    }
+    if (x >= s->width) {
+        x = s->width - 1;
+    }
+
+    s->x = x;
+    s->y = y;
+}
+
+static void vc_putchar(VCChardev *vc, int ch)
+{
+    QemuTextConsole *s = vc->console;
+    int i;
+    int x, y;
+    char response[40];
+
+    switch(vc->state) {
+    case TTY_STATE_NORM:
+        switch(ch) {
+        case '\r':  /* carriage return */
+            s->x = 0;
+            break;
+        case '\n':  /* newline */
+            vc_put_lf(vc);
+            break;
+        case '\b':  /* backspace */
+            if (s->x > 0)
+                s->x--;
+            break;
+        case '\t':  /* tabspace */
+            if (s->x + (8 - (s->x % 8)) > s->width) {
+                s->x = 0;
+                vc_put_lf(vc);
+            } else {
+                s->x = s->x + (8 - (s->x % 8));
+            }
+            break;
+        case '\a':  /* alert aka. bell */
+            /* TODO: has to be implemented */
+            break;
+        case 14:
+            /* SI (shift in), character set 0 (ignored) */
+            break;
+        case 15:
+            /* SO (shift out), character set 1 (ignored) */
+            break;
+        case 27:    /* esc (introducing an escape sequence) */
+            vc->state = TTY_STATE_ESC;
+            break;
+        default:
+            vc_put_one(vc, ch);
+            break;
+        }
+        break;
+    case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
+        if (ch == '[') {
+            for(i=0;i<MAX_ESC_PARAMS;i++)
+                vc->esc_params[i] = 0;
+            vc->nb_esc_params = 0;
+            vc->state = TTY_STATE_CSI;
+        } else {
+            vc->state = TTY_STATE_NORM;
+        }
+        break;
+    case TTY_STATE_CSI: /* handle escape sequence parameters */
+        if (ch >= '0' && ch <= '9') {
+            if (vc->nb_esc_params < MAX_ESC_PARAMS) {
+                int *param = &vc->esc_params[vc->nb_esc_params];
+                int digit = (ch - '0');
+
+                *param = (*param <= (INT_MAX - digit) / 10) ?
+                         *param * 10 + digit : INT_MAX;
+            }
+        } else {
+            if (vc->nb_esc_params < MAX_ESC_PARAMS)
+                vc->nb_esc_params++;
+            if (ch == ';' || ch == '?') {
+                break;
+            }
+            trace_console_putchar_csi(vc->esc_params[0], vc->esc_params[1],
+                                      ch, vc->nb_esc_params);
+            vc->state = TTY_STATE_NORM;
+            switch(ch) {
+            case 'A':
+                /* move cursor up */
+                if (vc->esc_params[0] == 0) {
+                    vc->esc_params[0] = 1;
+                }
+                vc_set_cursor(vc, s->x, s->y - vc->esc_params[0]);
+                break;
+            case 'B':
+                /* move cursor down */
+                if (vc->esc_params[0] == 0) {
+                    vc->esc_params[0] = 1;
+                }
+                vc_set_cursor(vc, s->x, s->y + vc->esc_params[0]);
+                break;
+            case 'C':
+                /* move cursor right */
+                if (vc->esc_params[0] == 0) {
+                    vc->esc_params[0] = 1;
+                }
+                vc_set_cursor(vc, s->x + vc->esc_params[0], s->y);
+                break;
+            case 'D':
+                /* move cursor left */
+                if (vc->esc_params[0] == 0) {
+                    vc->esc_params[0] = 1;
+                }
+                vc_set_cursor(vc, s->x - vc->esc_params[0], s->y);
+                break;
+            case 'G':
+                /* move cursor to column */
+                vc_set_cursor(vc, vc->esc_params[0] - 1, s->y);
+                break;
+            case 'f':
+            case 'H':
+                /* move cursor to row, column */
+                vc_set_cursor(vc, vc->esc_params[1] - 1, vc->esc_params[0] - 1);
+                break;
+            case 'J':
+                switch (vc->esc_params[0]) {
+                case 0:
+                    /* clear to end of screen */
+                    for (y = s->y; y < s->height; y++) {
+                        for (x = 0; x < s->width; x++) {
+                            if (y == s->y && x < s->x) {
+                                continue;
+                            }
+                            vc_clear_xy(vc, x, y);
+                        }
+                    }
+                    break;
+                case 1:
+                    /* clear from beginning of screen */
+                    for (y = 0; y <= s->y; y++) {
+                        for (x = 0; x < s->width; x++) {
+                            if (y == s->y && x > s->x) {
+                                break;
+                            }
+                            vc_clear_xy(vc, x, y);
+                        }
+                    }
+                    break;
+                case 2:
+                    /* clear entire screen */
+                    for (y = 0; y <= s->height; y++) {
+                        for (x = 0; x < s->width; x++) {
+                            vc_clear_xy(vc, x, y);
+                        }
+                    }
+                    break;
+                }
+                break;
+            case 'K':
+                switch (vc->esc_params[0]) {
+                case 0:
+                    /* clear to eol */
+                    for(x = s->x; x < s->width; x++) {
+                        vc_clear_xy(vc, x, s->y);
+                    }
+                    break;
+                case 1:
+                    /* clear from beginning of line */
+                    for (x = 0; x <= s->x && x < s->width; x++) {
+                        vc_clear_xy(vc, x, s->y);
+                    }
+                    break;
+                case 2:
+                    /* clear entire line */
+                    for(x = 0; x < s->width; x++) {
+                        vc_clear_xy(vc, x, s->y);
+                    }
+                    break;
+                }
+                break;
+            case 'm':
+                vc_handle_escape(vc);
+                break;
+            case 'n':
+                switch (vc->esc_params[0]) {
+                case 5:
+                    /* report console status (always succeed)*/
+                    vc_respond_str(vc, "\033[0n");
+                    break;
+                case 6:
+                    /* report cursor position */
+                    sprintf(response, "\033[%d;%dR",
+                           (s->y_base + s->y) % s->total_height + 1,
+                            s->x + 1);
+                    vc_respond_str(vc, response);
+                    break;
+                }
+                break;
+            case 's':
+                /* save cursor position */
+                vc->x_saved = s->x;
+                vc->y_saved = s->y;
+                break;
+            case 'u':
+                /* restore cursor position */
+                s->x = vc->x_saved;
+                s->y = vc->y_saved;
+                break;
+            default:
+                trace_console_putchar_unhandled(ch);
+                break;
+            }
+            break;
+        }
+    }
+}
+
+#define TYPE_CHARDEV_VC "chardev-vc"
+DECLARE_INSTANCE_CHECKER(VCChardev, VC_CHARDEV,
+                         TYPE_CHARDEV_VC)
+
+static int vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
+{
+    VCChardev *drv = VC_CHARDEV(chr);
+    QemuTextConsole *s = drv->console;
+    int i;
+
+    s->update_x0 = s->width * FONT_WIDTH;
+    s->update_y0 = s->height * FONT_HEIGHT;
+    s->update_x1 = 0;
+    s->update_y1 = 0;
+    console_show_cursor(s, 0);
+    for(i = 0; i < len; i++) {
+        vc_putchar(drv, buf[i]);
+    }
+    console_show_cursor(s, 1);
+    if (s->update_x0 < s->update_x1) {
+        dpy_gfx_update(QEMU_CONSOLE(s), s->update_x0, s->update_y0,
+                       s->update_x1 - s->update_x0,
+                       s->update_y1 - s->update_y0);
+    }
+    return len;
+}
+
+void qemu_text_console_update_cursor(void)
+{
+    cursor_visible_phase = !cursor_visible_phase;
+
+    if (qemu_invalidate_text_consoles()) {
+        timer_mod(cursor_timer,
+                  qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + CONSOLE_CURSOR_PERIOD / 2);
+    }
+}
+
+static void
+cursor_timer_cb(void *opaque)
+{
+    qemu_text_console_update_cursor();
+}
+
+static void text_console_invalidate(void *opaque)
+{
+    QemuTextConsole *s = QEMU_TEXT_CONSOLE(opaque);
+
+    if (!QEMU_IS_FIXED_TEXT_CONSOLE(s)) {
+        text_console_resize(QEMU_TEXT_CONSOLE(s));
+    }
+    console_refresh(s);
+}
+
+static void
+qemu_text_console_finalize(Object *obj)
+{
+}
+
+static void
+qemu_text_console_class_init(ObjectClass *oc, void *data)
+{
+    if (!cursor_timer) {
+        cursor_timer = timer_new_ms(QEMU_CLOCK_REALTIME, cursor_timer_cb, NULL);
+    }
+}
+
+static const GraphicHwOps text_console_ops = {
+    .invalidate  = text_console_invalidate,
+    .text_update = text_console_update,
+};
+
+static void
+qemu_text_console_init(Object *obj)
+{
+    QemuTextConsole *c = QEMU_TEXT_CONSOLE(obj);
+
+    fifo8_create(&c->out_fifo, 16);
+    c->total_height = DEFAULT_BACKSCROLL;
+    QEMU_CONSOLE(c)->hw_ops = &text_console_ops;
+    QEMU_CONSOLE(c)->hw = c;
+}
+
+static void
+qemu_fixed_text_console_finalize(Object *obj)
+{
+}
+
+static void
+qemu_fixed_text_console_class_init(ObjectClass *oc, void *data)
+{
+}
+
+static void
+qemu_fixed_text_console_init(Object *obj)
+{
+}
+
+static void vc_chr_accept_input(Chardev *chr)
+{
+    VCChardev *drv = VC_CHARDEV(chr);
+
+    kbd_send_chars(drv->console);
+}
+
+static void vc_chr_set_echo(Chardev *chr, bool echo)
+{
+    VCChardev *drv = VC_CHARDEV(chr);
+
+    drv->console->echo = echo;
+}
+
+void qemu_text_console_select(QemuTextConsole *c)
+{
+    dpy_text_resize(QEMU_CONSOLE(c), c->width, c->height);
+    qemu_text_console_update_cursor();
+}
+
+static void vc_chr_open(Chardev *chr,
+                        ChardevBackend *backend,
+                        bool *be_opened,
+                        Error **errp)
+{
+    ChardevVC *vc = backend->u.vc.data;
+    VCChardev *drv = VC_CHARDEV(chr);
+    QemuTextConsole *s;
+    unsigned width = 0;
+    unsigned height = 0;
+
+    if (vc->has_width) {
+        width = vc->width;
+    } else if (vc->has_cols) {
+        width = vc->cols * FONT_WIDTH;
+    }
+
+    if (vc->has_height) {
+        height = vc->height;
+    } else if (vc->has_rows) {
+        height = vc->rows * FONT_HEIGHT;
+    }
+
+    trace_console_txt_new(width, height);
+    if (width == 0 || height == 0) {
+        s = QEMU_TEXT_CONSOLE(object_new(TYPE_QEMU_TEXT_CONSOLE));
+        width = qemu_console_get_width(NULL, 80 * FONT_WIDTH);
+        height = qemu_console_get_height(NULL, 24 * FONT_HEIGHT);
+    } else {
+        s = QEMU_TEXT_CONSOLE(object_new(TYPE_QEMU_FIXED_TEXT_CONSOLE));
+    }
+
+    dpy_gfx_replace_surface(QEMU_CONSOLE(s), qemu_create_displaysurface(width, height));
+
+    s->chr = chr;
+    drv->console = s;
+
+    /* set current text attributes to default */
+    drv->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
+    text_console_resize(s);
+
+    if (chr->label) {
+        char *msg;
+
+        drv->t_attrib.bgcol = QEMU_COLOR_BLUE;
+        msg = g_strdup_printf("%s console\r\n", chr->label);
+        qemu_chr_write(chr, (uint8_t *)msg, strlen(msg), true);
+        g_free(msg);
+        drv->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
+    }
+
+    *be_opened = true;
+}
+
+static void vc_chr_parse(QemuOpts *opts, ChardevBackend *backend, Error **errp)
+{
+    int val;
+    ChardevVC *vc;
+
+    backend->type = CHARDEV_BACKEND_KIND_VC;
+    vc = backend->u.vc.data = g_new0(ChardevVC, 1);
+    qemu_chr_parse_common(opts, qapi_ChardevVC_base(vc));
+
+    val = qemu_opt_get_number(opts, "width", 0);
+    if (val != 0) {
+        vc->has_width = true;
+        vc->width = val;
+    }
+
+    val = qemu_opt_get_number(opts, "height", 0);
+    if (val != 0) {
+        vc->has_height = true;
+        vc->height = val;
+    }
+
+    val = qemu_opt_get_number(opts, "cols", 0);
+    if (val != 0) {
+        vc->has_cols = true;
+        vc->cols = val;
+    }
+
+    val = qemu_opt_get_number(opts, "rows", 0);
+    if (val != 0) {
+        vc->has_rows = true;
+        vc->rows = val;
+    }
+}
+
+static void char_vc_class_init(ObjectClass *oc, void *data)
+{
+    ChardevClass *cc = CHARDEV_CLASS(oc);
+
+    cc->parse = vc_chr_parse;
+    cc->open = vc_chr_open;
+    cc->chr_write = vc_chr_write;
+    cc->chr_accept_input = vc_chr_accept_input;
+    cc->chr_set_echo = vc_chr_set_echo;
+}
+
+static const TypeInfo char_vc_type_info = {
+    .name = TYPE_CHARDEV_VC,
+    .parent = TYPE_CHARDEV,
+    .instance_size = sizeof(VCChardev),
+    .class_init = char_vc_class_init,
+};
+
+void qemu_console_early_init(void)
+{
+    /* set the default vc driver */
+    if (!object_class_by_name(TYPE_CHARDEV_VC)) {
+        type_register(&char_vc_type_info);
+    }
+}
diff --git a/ui/console.c b/ui/console.c
index d9ac3717ff..da341f08da 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -29,68 +29,16 @@
 #include "qapi/qapi-commands-ui.h"
 #include "qapi/visitor.h"
 #include "qemu/coroutine.h"
-#include "qemu/fifo8.h"
 #include "qemu/error-report.h"
 #include "qemu/main-loop.h"
 #include "qemu/module.h"
 #include "qemu/option.h"
-#include "qemu/timer.h"
 #include "chardev/char.h"
 #include "trace.h"
 #include "exec/memory.h"
 #include "qom/object.h"
 
-#define DEFAULT_BACKSCROLL 512
-#define CONSOLE_CURSOR_PERIOD 500
-
-typedef struct TextAttributes {
-    uint8_t fgcol:4;
-    uint8_t bgcol:4;
-    uint8_t bold:1;
-    uint8_t uline:1;
-    uint8_t blink:1;
-    uint8_t invers:1;
-    uint8_t unvisible:1;
-} TextAttributes;
-
-#define TEXT_ATTRIBUTES_DEFAULT ((TextAttributes) { \
-    .fgcol = QEMU_COLOR_WHITE,                      \
-    .bgcol = QEMU_COLOR_BLACK                       \
-})
-
-typedef struct TextCell {
-    uint8_t ch;
-    TextAttributes t_attrib;
-} TextCell;
-
-#define MAX_ESC_PARAMS 3
-
-enum TTYState {
-    TTY_STATE_NORM,
-    TTY_STATE_ESC,
-    TTY_STATE_CSI,
-};
-
-struct QemuConsole {
-    Object parent;
-
-    int index;
-    DisplayState *ds;
-    DisplaySurface *surface;
-    DisplayScanout scanout;
-    int dcls;
-    DisplayGLCtx *gl;
-    int gl_block;
-    QEMUTimer *gl_unblock_timer;
-    int window_id;
-    QemuUIInfo ui_info;
-    QEMUTimer *ui_timer;
-    const GraphicHwOps *hw_ops;
-    void *hw;
-    CoQueue dump_queue;
-
-    QTAILQ_ENTRY(QemuConsole) next;
-};
+#include "console-priv.h"
 
 OBJECT_DEFINE_ABSTRACT_TYPE(QemuConsole, qemu_console, QEMU_CONSOLE, OBJECT)
 
@@ -108,54 +56,6 @@ typedef QemuConsoleClass QemuGraphicConsoleClass;
 
 OBJECT_DEFINE_TYPE(QemuGraphicConsole, qemu_graphic_console, QEMU_GRAPHIC_CONSOLE, QEMU_CONSOLE)
 
-typedef struct QemuTextConsole {
-    QemuConsole parent;
-
-    int width;
-    int height;
-    int total_height;
-    int backscroll_height;
-    int x, y;
-    int y_displayed;
-    int y_base;
-    TextCell *cells;
-    int text_x[2], text_y[2], cursor_invalidate;
-    int echo;
-
-    int update_x0;
-    int update_y0;
-    int update_x1;
-    int update_y1;
-
-    Chardev *chr;
-    /* fifo for key pressed */
-    Fifo8 out_fifo;
-} QemuTextConsole;
-
-typedef QemuConsoleClass QemuTextConsoleClass;
-
-OBJECT_DEFINE_TYPE(QemuTextConsole, qemu_text_console, QEMU_TEXT_CONSOLE, QEMU_CONSOLE)
-
-typedef struct QemuFixedTextConsole {
-    QemuTextConsole parent;
-} QemuFixedTextConsole;
-
-typedef QemuTextConsoleClass QemuFixedTextConsoleClass;
-
-OBJECT_DEFINE_TYPE(QemuFixedTextConsole, qemu_fixed_text_console, QEMU_FIXED_TEXT_CONSOLE, QEMU_TEXT_CONSOLE)
-
-struct VCChardev {
-    Chardev parent;
-    QemuTextConsole *console;
-
-    enum TTYState state;
-    int esc_params[MAX_ESC_PARAMS];
-    int nb_esc_params;
-    TextAttributes t_attrib; /* currently active text attributes */
-    int x_saved, y_saved;
-};
-typedef struct VCChardev VCChardev;
-
 struct DisplayState {
     QEMUTimer *gui_timer;
     uint64_t last_update;
@@ -169,12 +69,9 @@ static DisplayState *display_state;
 static QemuConsole *active_console;
 static QTAILQ_HEAD(, QemuConsole) consoles =
     QTAILQ_HEAD_INITIALIZER(consoles);
-static bool cursor_visible_phase;
-static QEMUTimer *cursor_timer;
 
 static void dpy_refresh(DisplayState *s);
 static DisplayState *get_alloc_displaystate(void);
-static void qemu_text_console_update_cursor(void *opaque);
 static bool displaychangelistener_has_dmabuf(DisplayChangeListener *dcl);
 static bool console_compatible_with(QemuConsole *con,
                                     DisplayChangeListener *dcl, Error **errp);
@@ -330,663 +227,6 @@ void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata)
     }
 }
 
-static void qemu_console_fill_rect(QemuConsole *con, int posx, int posy,
-                                   int width, int height, pixman_color_t color)
-{
-    DisplaySurface *surface = qemu_console_surface(con);
-    pixman_rectangle16_t rect = {
-        .x = posx, .y = posy, .width = width, .height = height
-    };
-
-    assert(surface);
-    pixman_image_fill_rectangles(PIXMAN_OP_SRC, surface->image,
-                                 &color, 1, &rect);
-}
-
-/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
-static void qemu_console_bitblt(QemuConsole *con,
-                                int xs, int ys, int xd, int yd, int w, int h)
-{
-    DisplaySurface *surface = qemu_console_surface(con);
-
-    assert(surface);
-    pixman_image_composite(PIXMAN_OP_SRC,
-                           surface->image, NULL, surface->image,
-                           xs, ys, 0, 0, xd, yd, w, h);
-}
-
-/***********************************************************/
-/* basic char display */
-
-#define FONT_HEIGHT 16
-#define FONT_WIDTH 8
-
-#include "vgafont.h"
-
-static const pixman_color_t color_table_rgb[2][8] = {
-    {   /* dark */
-        [QEMU_COLOR_BLACK]   = QEMU_PIXMAN_COLOR_BLACK,
-        [QEMU_COLOR_BLUE]    = QEMU_PIXMAN_COLOR(0x00, 0x00, 0xaa),  /* blue */
-        [QEMU_COLOR_GREEN]   = QEMU_PIXMAN_COLOR(0x00, 0xaa, 0x00),  /* green */
-        [QEMU_COLOR_CYAN]    = QEMU_PIXMAN_COLOR(0x00, 0xaa, 0xaa),  /* cyan */
-        [QEMU_COLOR_RED]     = QEMU_PIXMAN_COLOR(0xaa, 0x00, 0x00),  /* red */
-        [QEMU_COLOR_MAGENTA] = QEMU_PIXMAN_COLOR(0xaa, 0x00, 0xaa),  /* magenta */
-        [QEMU_COLOR_YELLOW]  = QEMU_PIXMAN_COLOR(0xaa, 0xaa, 0x00),  /* yellow */
-        [QEMU_COLOR_WHITE]   = QEMU_PIXMAN_COLOR_GRAY,
-    },
-    {   /* bright */
-        [QEMU_COLOR_BLACK]   = QEMU_PIXMAN_COLOR_BLACK,
-        [QEMU_COLOR_BLUE]    = QEMU_PIXMAN_COLOR(0x00, 0x00, 0xff),  /* blue */
-        [QEMU_COLOR_GREEN]   = QEMU_PIXMAN_COLOR(0x00, 0xff, 0x00),  /* green */
-        [QEMU_COLOR_CYAN]    = QEMU_PIXMAN_COLOR(0x00, 0xff, 0xff),  /* cyan */
-        [QEMU_COLOR_RED]     = QEMU_PIXMAN_COLOR(0xff, 0x00, 0x00),  /* red */
-        [QEMU_COLOR_MAGENTA] = QEMU_PIXMAN_COLOR(0xff, 0x00, 0xff),  /* magenta */
-        [QEMU_COLOR_YELLOW]  = QEMU_PIXMAN_COLOR(0xff, 0xff, 0x00),  /* yellow */
-        [QEMU_COLOR_WHITE]   = QEMU_PIXMAN_COLOR(0xff, 0xff, 0xff),  /* white */
-    }
-};
-
-static void vga_putcharxy(QemuConsole *s, int x, int y, int ch,
-                          TextAttributes *t_attrib)
-{
-    static pixman_image_t *glyphs[256];
-    DisplaySurface *surface = qemu_console_surface(s);
-    pixman_color_t fgcol, bgcol;
-
-    assert(surface);
-    if (t_attrib->invers) {
-        bgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
-        fgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
-    } else {
-        fgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
-        bgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
-    }
-
-    if (!glyphs[ch]) {
-        glyphs[ch] = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, ch);
-    }
-    qemu_pixman_glyph_render(glyphs[ch], surface->image,
-                             &fgcol, &bgcol, x, y, FONT_WIDTH, FONT_HEIGHT);
-}
-
-static void text_console_resize(QemuTextConsole *t)
-{
-    QemuConsole *s = QEMU_CONSOLE(t);
-    TextCell *cells, *c, *c1;
-    int w1, x, y, last_width, w, h;
-
-    assert(s->scanout.kind == SCANOUT_SURFACE);
-
-    w = surface_width(s->surface) / FONT_WIDTH;
-    h = surface_height(s->surface) / FONT_HEIGHT;
-    if (w == t->width && h == t->height) {
-        return;
-    }
-
-    last_width = t->width;
-    t->width = w;
-    t->height = h;
-
-    w1 = MIN(t->width, last_width);
-
-    cells = g_new(TextCell, t->width * t->total_height + 1);
-    for (y = 0; y < t->total_height; y++) {
-        c = &cells[y * t->width];
-        if (w1 > 0) {
-            c1 = &t->cells[y * last_width];
-            for (x = 0; x < w1; x++) {
-                *c++ = *c1++;
-            }
-        }
-        for (x = w1; x < t->width; x++) {
-            c->ch = ' ';
-            c->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
-            c++;
-        }
-    }
-    g_free(t->cells);
-    t->cells = cells;
-}
-
-static void invalidate_xy(QemuTextConsole *s, int x, int y)
-{
-    if (!qemu_console_is_visible(QEMU_CONSOLE(s))) {
-        return;
-    }
-    if (s->update_x0 > x * FONT_WIDTH)
-        s->update_x0 = x * FONT_WIDTH;
-    if (s->update_y0 > y * FONT_HEIGHT)
-        s->update_y0 = y * FONT_HEIGHT;
-    if (s->update_x1 < (x + 1) * FONT_WIDTH)
-        s->update_x1 = (x + 1) * FONT_WIDTH;
-    if (s->update_y1 < (y + 1) * FONT_HEIGHT)
-        s->update_y1 = (y + 1) * FONT_HEIGHT;
-}
-
-static void vc_update_xy(VCChardev *vc, int x, int y)
-{
-    QemuTextConsole *s = vc->console;
-    TextCell *c;
-    int y1, y2;
-
-    s->text_x[0] = MIN(s->text_x[0], x);
-    s->text_x[1] = MAX(s->text_x[1], x);
-    s->text_y[0] = MIN(s->text_y[0], y);
-    s->text_y[1] = MAX(s->text_y[1], y);
-
-    y1 = (s->y_base + y) % s->total_height;
-    y2 = y1 - s->y_displayed;
-    if (y2 < 0) {
-        y2 += s->total_height;
-    }
-    if (y2 < s->height) {
-        if (x >= s->width) {
-            x = s->width - 1;
-        }
-        c = &s->cells[y1 * s->width + x];
-        vga_putcharxy(QEMU_CONSOLE(s), x, y2, c->ch,
-                      &(c->t_attrib));
-        invalidate_xy(s, x, y2);
-    }
-}
-
-static void console_show_cursor(QemuTextConsole *s, int show)
-{
-    TextCell *c;
-    int y, y1;
-    int x = s->x;
-
-    s->cursor_invalidate = 1;
-
-    if (x >= s->width) {
-        x = s->width - 1;
-    }
-    y1 = (s->y_base + s->y) % s->total_height;
-    y = y1 - s->y_displayed;
-    if (y < 0) {
-        y += s->total_height;
-    }
-    if (y < s->height) {
-        c = &s->cells[y1 * s->width + x];
-        if (show && cursor_visible_phase) {
-            TextAttributes t_attrib = TEXT_ATTRIBUTES_DEFAULT;
-            t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
-            vga_putcharxy(QEMU_CONSOLE(s), x, y, c->ch, &t_attrib);
-        } else {
-            vga_putcharxy(QEMU_CONSOLE(s), x, y, c->ch, &(c->t_attrib));
-        }
-        invalidate_xy(s, x, y);
-    }
-}
-
-static void console_refresh(QemuTextConsole *s)
-{
-    DisplaySurface *surface = qemu_console_surface(QEMU_CONSOLE(s));
-    TextCell *c;
-    int x, y, y1;
-
-    assert(surface);
-    s->text_x[0] = 0;
-    s->text_y[0] = 0;
-    s->text_x[1] = s->width - 1;
-    s->text_y[1] = s->height - 1;
-    s->cursor_invalidate = 1;
-
-    qemu_console_fill_rect(QEMU_CONSOLE(s), 0, 0, surface_width(surface), surface_height(surface),
-                           color_table_rgb[0][QEMU_COLOR_BLACK]);
-    y1 = s->y_displayed;
-    for (y = 0; y < s->height; y++) {
-        c = s->cells + y1 * s->width;
-        for (x = 0; x < s->width; x++) {
-            vga_putcharxy(QEMU_CONSOLE(s), x, y, c->ch,
-                          &(c->t_attrib));
-            c++;
-        }
-        if (++y1 == s->total_height) {
-            y1 = 0;
-        }
-    }
-    console_show_cursor(s, 1);
-    dpy_gfx_update(QEMU_CONSOLE(s), 0, 0,
-                   surface_width(surface), surface_height(surface));
-}
-
-static void console_scroll(QemuTextConsole *s, int ydelta)
-{
-    int i, y1;
-
-    if (ydelta > 0) {
-        for(i = 0; i < ydelta; i++) {
-            if (s->y_displayed == s->y_base)
-                break;
-            if (++s->y_displayed == s->total_height)
-                s->y_displayed = 0;
-        }
-    } else {
-        ydelta = -ydelta;
-        i = s->backscroll_height;
-        if (i > s->total_height - s->height)
-            i = s->total_height - s->height;
-        y1 = s->y_base - i;
-        if (y1 < 0)
-            y1 += s->total_height;
-        for(i = 0; i < ydelta; i++) {
-            if (s->y_displayed == y1)
-                break;
-            if (--s->y_displayed < 0)
-                s->y_displayed = s->total_height - 1;
-        }
-    }
-    console_refresh(s);
-}
-
-static void vc_put_lf(VCChardev *vc)
-{
-    QemuTextConsole *s = vc->console;
-    TextCell *c;
-    int x, y1;
-
-    s->y++;
-    if (s->y >= s->height) {
-        s->y = s->height - 1;
-
-        if (s->y_displayed == s->y_base) {
-            if (++s->y_displayed == s->total_height)
-                s->y_displayed = 0;
-        }
-        if (++s->y_base == s->total_height)
-            s->y_base = 0;
-        if (s->backscroll_height < s->total_height)
-            s->backscroll_height++;
-        y1 = (s->y_base + s->height - 1) % s->total_height;
-        c = &s->cells[y1 * s->width];
-        for(x = 0; x < s->width; x++) {
-            c->ch = ' ';
-            c->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
-            c++;
-        }
-        if (s->y_displayed == s->y_base) {
-            s->text_x[0] = 0;
-            s->text_y[0] = 0;
-            s->text_x[1] = s->width - 1;
-            s->text_y[1] = s->height - 1;
-
-            qemu_console_bitblt(QEMU_CONSOLE(s), 0, FONT_HEIGHT, 0, 0,
-                                s->width * FONT_WIDTH,
-                                (s->height - 1) * FONT_HEIGHT);
-            qemu_console_fill_rect(QEMU_CONSOLE(s), 0, (s->height - 1) * FONT_HEIGHT,
-                                   s->width * FONT_WIDTH, FONT_HEIGHT,
-                                   color_table_rgb[0][TEXT_ATTRIBUTES_DEFAULT.bgcol]);
-            s->update_x0 = 0;
-            s->update_y0 = 0;
-            s->update_x1 = s->width * FONT_WIDTH;
-            s->update_y1 = s->height * FONT_HEIGHT;
-        }
-    }
-}
-
-/* Set console attributes depending on the current escape codes.
- * NOTE: I know this code is not very efficient (checking every color for it
- * self) but it is more readable and better maintainable.
- */
-static void vc_handle_escape(VCChardev *vc)
-{
-    int i;
-
-    for (i = 0; i < vc->nb_esc_params; i++) {
-        switch (vc->esc_params[i]) {
-            case 0: /* reset all console attributes to default */
-                vc->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
-                break;
-            case 1:
-                vc->t_attrib.bold = 1;
-                break;
-            case 4:
-                vc->t_attrib.uline = 1;
-                break;
-            case 5:
-                vc->t_attrib.blink = 1;
-                break;
-            case 7:
-                vc->t_attrib.invers = 1;
-                break;
-            case 8:
-                vc->t_attrib.unvisible = 1;
-                break;
-            case 22:
-                vc->t_attrib.bold = 0;
-                break;
-            case 24:
-                vc->t_attrib.uline = 0;
-                break;
-            case 25:
-                vc->t_attrib.blink = 0;
-                break;
-            case 27:
-                vc->t_attrib.invers = 0;
-                break;
-            case 28:
-                vc->t_attrib.unvisible = 0;
-                break;
-            /* set foreground color */
-            case 30:
-                vc->t_attrib.fgcol = QEMU_COLOR_BLACK;
-                break;
-            case 31:
-                vc->t_attrib.fgcol = QEMU_COLOR_RED;
-                break;
-            case 32:
-                vc->t_attrib.fgcol = QEMU_COLOR_GREEN;
-                break;
-            case 33:
-                vc->t_attrib.fgcol = QEMU_COLOR_YELLOW;
-                break;
-            case 34:
-                vc->t_attrib.fgcol = QEMU_COLOR_BLUE;
-                break;
-            case 35:
-                vc->t_attrib.fgcol = QEMU_COLOR_MAGENTA;
-                break;
-            case 36:
-                vc->t_attrib.fgcol = QEMU_COLOR_CYAN;
-                break;
-            case 37:
-                vc->t_attrib.fgcol = QEMU_COLOR_WHITE;
-                break;
-            /* set background color */
-            case 40:
-                vc->t_attrib.bgcol = QEMU_COLOR_BLACK;
-                break;
-            case 41:
-                vc->t_attrib.bgcol = QEMU_COLOR_RED;
-                break;
-            case 42:
-                vc->t_attrib.bgcol = QEMU_COLOR_GREEN;
-                break;
-            case 43:
-                vc->t_attrib.bgcol = QEMU_COLOR_YELLOW;
-                break;
-            case 44:
-                vc->t_attrib.bgcol = QEMU_COLOR_BLUE;
-                break;
-            case 45:
-                vc->t_attrib.bgcol = QEMU_COLOR_MAGENTA;
-                break;
-            case 46:
-                vc->t_attrib.bgcol = QEMU_COLOR_CYAN;
-                break;
-            case 47:
-                vc->t_attrib.bgcol = QEMU_COLOR_WHITE;
-                break;
-        }
-    }
-}
-
-static void vc_clear_xy(VCChardev *vc, int x, int y)
-{
-    QemuTextConsole *s = vc->console;
-    int y1 = (s->y_base + y) % s->total_height;
-    if (x >= s->width) {
-        x = s->width - 1;
-    }
-    TextCell *c = &s->cells[y1 * s->width + x];
-    c->ch = ' ';
-    c->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
-    vc_update_xy(vc, x, y);
-}
-
-static void vc_put_one(VCChardev *vc, int ch)
-{
-    QemuTextConsole *s = vc->console;
-    TextCell *c;
-    int y1;
-    if (s->x >= s->width) {
-        /* line wrap */
-        s->x = 0;
-        vc_put_lf(vc);
-    }
-    y1 = (s->y_base + s->y) % s->total_height;
-    c = &s->cells[y1 * s->width + s->x];
-    c->ch = ch;
-    c->t_attrib = vc->t_attrib;
-    vc_update_xy(vc, s->x, s->y);
-    s->x++;
-}
-
-static void vc_respond_str(VCChardev *vc, const char *buf)
-{
-    while (*buf) {
-        vc_put_one(vc, *buf);
-        buf++;
-    }
-}
-
-/* set cursor, checking bounds */
-static void vc_set_cursor(VCChardev *vc, int x, int y)
-{
-    QemuTextConsole *s = vc->console;
-
-    if (x < 0) {
-        x = 0;
-    }
-    if (y < 0) {
-        y = 0;
-    }
-    if (y >= s->height) {
-        y = s->height - 1;
-    }
-    if (x >= s->width) {
-        x = s->width - 1;
-    }
-
-    s->x = x;
-    s->y = y;
-}
-
-static void vc_putchar(VCChardev *vc, int ch)
-{
-    QemuTextConsole *s = vc->console;
-    int i;
-    int x, y;
-    char response[40];
-
-    switch(vc->state) {
-    case TTY_STATE_NORM:
-        switch(ch) {
-        case '\r':  /* carriage return */
-            s->x = 0;
-            break;
-        case '\n':  /* newline */
-            vc_put_lf(vc);
-            break;
-        case '\b':  /* backspace */
-            if (s->x > 0)
-                s->x--;
-            break;
-        case '\t':  /* tabspace */
-            if (s->x + (8 - (s->x % 8)) > s->width) {
-                s->x = 0;
-                vc_put_lf(vc);
-            } else {
-                s->x = s->x + (8 - (s->x % 8));
-            }
-            break;
-        case '\a':  /* alert aka. bell */
-            /* TODO: has to be implemented */
-            break;
-        case 14:
-            /* SI (shift in), character set 0 (ignored) */
-            break;
-        case 15:
-            /* SO (shift out), character set 1 (ignored) */
-            break;
-        case 27:    /* esc (introducing an escape sequence) */
-            vc->state = TTY_STATE_ESC;
-            break;
-        default:
-            vc_put_one(vc, ch);
-            break;
-        }
-        break;
-    case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
-        if (ch == '[') {
-            for(i=0;i<MAX_ESC_PARAMS;i++)
-                vc->esc_params[i] = 0;
-            vc->nb_esc_params = 0;
-            vc->state = TTY_STATE_CSI;
-        } else {
-            vc->state = TTY_STATE_NORM;
-        }
-        break;
-    case TTY_STATE_CSI: /* handle escape sequence parameters */
-        if (ch >= '0' && ch <= '9') {
-            if (vc->nb_esc_params < MAX_ESC_PARAMS) {
-                int *param = &vc->esc_params[vc->nb_esc_params];
-                int digit = (ch - '0');
-
-                *param = (*param <= (INT_MAX - digit) / 10) ?
-                         *param * 10 + digit : INT_MAX;
-            }
-        } else {
-            if (vc->nb_esc_params < MAX_ESC_PARAMS)
-                vc->nb_esc_params++;
-            if (ch == ';' || ch == '?') {
-                break;
-            }
-            trace_console_putchar_csi(vc->esc_params[0], vc->esc_params[1],
-                                      ch, vc->nb_esc_params);
-            vc->state = TTY_STATE_NORM;
-            switch(ch) {
-            case 'A':
-                /* move cursor up */
-                if (vc->esc_params[0] == 0) {
-                    vc->esc_params[0] = 1;
-                }
-                vc_set_cursor(vc, s->x, s->y - vc->esc_params[0]);
-                break;
-            case 'B':
-                /* move cursor down */
-                if (vc->esc_params[0] == 0) {
-                    vc->esc_params[0] = 1;
-                }
-                vc_set_cursor(vc, s->x, s->y + vc->esc_params[0]);
-                break;
-            case 'C':
-                /* move cursor right */
-                if (vc->esc_params[0] == 0) {
-                    vc->esc_params[0] = 1;
-                }
-                vc_set_cursor(vc, s->x + vc->esc_params[0], s->y);
-                break;
-            case 'D':
-                /* move cursor left */
-                if (vc->esc_params[0] == 0) {
-                    vc->esc_params[0] = 1;
-                }
-                vc_set_cursor(vc, s->x - vc->esc_params[0], s->y);
-                break;
-            case 'G':
-                /* move cursor to column */
-                vc_set_cursor(vc, vc->esc_params[0] - 1, s->y);
-                break;
-            case 'f':
-            case 'H':
-                /* move cursor to row, column */
-                vc_set_cursor(vc, vc->esc_params[1] - 1, vc->esc_params[0] - 1);
-                break;
-            case 'J':
-                switch (vc->esc_params[0]) {
-                case 0:
-                    /* clear to end of screen */
-                    for (y = s->y; y < s->height; y++) {
-                        for (x = 0; x < s->width; x++) {
-                            if (y == s->y && x < s->x) {
-                                continue;
-                            }
-                            vc_clear_xy(vc, x, y);
-                        }
-                    }
-                    break;
-                case 1:
-                    /* clear from beginning of screen */
-                    for (y = 0; y <= s->y; y++) {
-                        for (x = 0; x < s->width; x++) {
-                            if (y == s->y && x > s->x) {
-                                break;
-                            }
-                            vc_clear_xy(vc, x, y);
-                        }
-                    }
-                    break;
-                case 2:
-                    /* clear entire screen */
-                    for (y = 0; y <= s->height; y++) {
-                        for (x = 0; x < s->width; x++) {
-                            vc_clear_xy(vc, x, y);
-                        }
-                    }
-                    break;
-                }
-                break;
-            case 'K':
-                switch (vc->esc_params[0]) {
-                case 0:
-                    /* clear to eol */
-                    for(x = s->x; x < s->width; x++) {
-                        vc_clear_xy(vc, x, s->y);
-                    }
-                    break;
-                case 1:
-                    /* clear from beginning of line */
-                    for (x = 0; x <= s->x && x < s->width; x++) {
-                        vc_clear_xy(vc, x, s->y);
-                    }
-                    break;
-                case 2:
-                    /* clear entire line */
-                    for(x = 0; x < s->width; x++) {
-                        vc_clear_xy(vc, x, s->y);
-                    }
-                    break;
-                }
-                break;
-            case 'm':
-                vc_handle_escape(vc);
-                break;
-            case 'n':
-                switch (vc->esc_params[0]) {
-                case 5:
-                    /* report console status (always succeed)*/
-                    vc_respond_str(vc, "\033[0n");
-                    break;
-                case 6:
-                    /* report cursor position */
-                    sprintf(response, "\033[%d;%dR",
-                           (s->y_base + s->y) % s->total_height + 1,
-                            s->x + 1);
-                    vc_respond_str(vc, response);
-                    break;
-                }
-                break;
-            case 's':
-                /* save cursor position */
-                vc->x_saved = s->x;
-                vc->y_saved = s->y;
-                break;
-            case 'u':
-                /* restore cursor position */
-                s->x = vc->x_saved;
-                s->y = vc->y_saved;
-                break;
-            default:
-                trace_console_putchar_unhandled(ch);
-                break;
-            }
-            break;
-        }
-    }
-}
-
 static void displaychangelistener_gfx_switch(DisplayChangeListener *dcl,
                                              struct DisplaySurface *new_surface,
                                              bool update)
@@ -1065,13 +305,6 @@ static void displaychangelistener_display_console(DisplayChangeListener *dcl,
     }
 }
 
-static void
-qemu_text_console_select(QemuTextConsole *c)
-{
-    dpy_text_resize(QEMU_CONSOLE(c), c->width, c->height);
-    qemu_text_console_update_cursor(NULL);
-}
-
 void console_select(unsigned int index)
 {
     DisplayChangeListener *dcl;
@@ -1096,101 +329,6 @@ void console_select(unsigned int index)
     }
 }
 
-#define TYPE_CHARDEV_VC "chardev-vc"
-DECLARE_INSTANCE_CHECKER(VCChardev, VC_CHARDEV,
-                         TYPE_CHARDEV_VC)
-
-static int vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
-{
-    VCChardev *drv = VC_CHARDEV(chr);
-    QemuTextConsole *s = drv->console;
-    int i;
-
-    s->update_x0 = s->width * FONT_WIDTH;
-    s->update_y0 = s->height * FONT_HEIGHT;
-    s->update_x1 = 0;
-    s->update_y1 = 0;
-    console_show_cursor(s, 0);
-    for(i = 0; i < len; i++) {
-        vc_putchar(drv, buf[i]);
-    }
-    console_show_cursor(s, 1);
-    if (s->update_x0 < s->update_x1) {
-        dpy_gfx_update(QEMU_CONSOLE(s), s->update_x0, s->update_y0,
-                       s->update_x1 - s->update_x0,
-                       s->update_y1 - s->update_y0);
-    }
-    return len;
-}
-
-static void kbd_send_chars(QemuTextConsole *s)
-{
-    uint32_t len, avail;
-
-    len = qemu_chr_be_can_write(s->chr);
-    avail = fifo8_num_used(&s->out_fifo);
-    while (len > 0 && avail > 0) {
-        const uint8_t *buf;
-        uint32_t size;
-
-        buf = fifo8_pop_buf(&s->out_fifo, MIN(len, avail), &size);
-        qemu_chr_be_write(s->chr, buf, size);
-        len = qemu_chr_be_can_write(s->chr);
-        avail -= size;
-    }
-}
-
-/* called when an ascii key is pressed */
-static void qemu_text_console_handle_keysym(QemuTextConsole *s, int keysym)
-{
-    uint8_t buf[16], *q;
-    int c;
-    uint32_t num_free;
-
-    switch(keysym) {
-    case QEMU_KEY_CTRL_UP:
-        console_scroll(s, -1);
-        break;
-    case QEMU_KEY_CTRL_DOWN:
-        console_scroll(s, 1);
-        break;
-    case QEMU_KEY_CTRL_PAGEUP:
-        console_scroll(s, -10);
-        break;
-    case QEMU_KEY_CTRL_PAGEDOWN:
-        console_scroll(s, 10);
-        break;
-    default:
-        /* convert the QEMU keysym to VT100 key string */
-        q = buf;
-        if (keysym >= 0xe100 && keysym <= 0xe11f) {
-            *q++ = '\033';
-            *q++ = '[';
-            c = keysym - 0xe100;
-            if (c >= 10)
-                *q++ = '0' + (c / 10);
-            *q++ = '0' + (c % 10);
-            *q++ = '~';
-        } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
-            *q++ = '\033';
-            *q++ = '[';
-            *q++ = keysym & 0xff;
-        } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
-            qemu_chr_write(s->chr, (uint8_t *)"\r", 1, true);
-            *q++ = '\n';
-        } else {
-            *q++ = keysym;
-        }
-        if (s->echo) {
-            qemu_chr_write(s->chr, buf, q - buf, true);
-        }
-        num_free = fifo8_num_free(&s->out_fifo);
-        fifo8_push_all(&s->out_fifo, buf, MIN(num_free, q - buf));
-        kbd_send_chars(s);
-        break;
-    }
-}
-
 void qemu_text_console_put_keysym(QemuTextConsole *s, int keysym)
 {
     if (!s) {
@@ -1249,45 +387,6 @@ void qemu_text_console_put_string(QemuTextConsole *s, const char *str, int len)
     }
 }
 
-static void text_console_invalidate(void *opaque)
-{
-    QemuTextConsole *s = QEMU_TEXT_CONSOLE(opaque);
-
-    if (!QEMU_IS_FIXED_TEXT_CONSOLE(s)) {
-        text_console_resize(QEMU_TEXT_CONSOLE(s));
-    }
-    console_refresh(s);
-}
-
-static void text_console_update(void *opaque, console_ch_t *chardata)
-{
-    QemuTextConsole *s = QEMU_TEXT_CONSOLE(opaque);
-    int i, j, src;
-
-    if (s->text_x[0] <= s->text_x[1]) {
-        src = (s->y_base + s->text_y[0]) * s->width;
-        chardata += s->text_y[0] * s->width;
-        for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
-            for (j = 0; j < s->width; j++, src++) {
-                console_write_ch(chardata ++,
-                                 ATTR2CHTYPE(s->cells[src].ch,
-                                             s->cells[src].t_attrib.fgcol,
-                                             s->cells[src].t_attrib.bgcol,
-                                             s->cells[src].t_attrib.bold));
-            }
-        dpy_text_update(QEMU_CONSOLE(s), s->text_x[0], s->text_y[0],
-                        s->text_x[1] - s->text_x[0], i - s->text_y[0]);
-        s->text_x[0] = s->width;
-        s->text_y[0] = s->height;
-        s->text_x[1] = 0;
-        s->text_y[1] = 0;
-    }
-    if (s->cursor_invalidate) {
-        dpy_text_cursor(QEMU_CONSOLE(s), s->x, s->y);
-        s->cursor_invalidate = 0;
-    }
-}
-
 static void
 qemu_console_register(QemuConsole *c)
 {
@@ -1396,51 +495,6 @@ qemu_graphic_console_init(Object *obj)
 {
 }
 
-static void
-qemu_text_console_finalize(Object *obj)
-{
-}
-
-static void
-qemu_text_console_class_init(ObjectClass *oc, void *data)
-{
-    if (!cursor_timer) {
-        cursor_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
-                                    qemu_text_console_update_cursor, NULL);
-    }
-}
-
-static const GraphicHwOps text_console_ops = {
-    .invalidate  = text_console_invalidate,
-    .text_update = text_console_update,
-};
-
-static void
-qemu_text_console_init(Object *obj)
-{
-    QemuTextConsole *c = QEMU_TEXT_CONSOLE(obj);
-
-    fifo8_create(&c->out_fifo, 16);
-    c->total_height = DEFAULT_BACKSCROLL;
-    QEMU_CONSOLE(c)->hw_ops = &text_console_ops;
-    QEMU_CONSOLE(c)->hw = c;
-}
-
-static void
-qemu_fixed_text_console_finalize(Object *obj)
-{
-}
-
-static void
-qemu_fixed_text_console_class_init(ObjectClass *oc, void *data)
-{
-}
-
-static void
-qemu_fixed_text_console_init(Object *obj)
-{
-}
-
 #ifdef WIN32
 void qemu_displaysurface_win32_set_handle(DisplaySurface *surface,
                                           HANDLE h, uint32_t offset)
@@ -1692,6 +746,7 @@ dcl_set_graphic_cursor(DisplayChangeListener *dcl, QemuGraphicConsole *con)
         dcl->ops->dpy_mouse_set(dcl, con->cursor_x, con->cursor_y, con->cursor_on);
     }
 }
+
 void register_displaychangelistener(DisplayChangeListener *dcl)
 {
     QemuConsole *con;
@@ -1712,7 +767,7 @@ void register_displaychangelistener(DisplayChangeListener *dcl)
     if (QEMU_IS_GRAPHIC_CONSOLE(con)) {
         dcl_set_graphic_cursor(dcl, QEMU_GRAPHIC_CONSOLE(con));
     }
-    qemu_text_console_update_cursor(NULL);
+    qemu_text_console_update_cursor();
 }
 
 void update_displaychangelistener(DisplayChangeListener *dcl,
@@ -2399,13 +1454,6 @@ bool qemu_console_is_multihead(DeviceState *dev)
     return false;
 }
 
-
-static const char *
-qemu_text_console_get_label(QemuTextConsole *c)
-{
-    return c->chr ? c->chr->label : NULL;
-}
-
 char *qemu_console_get_label(QemuConsole *con)
 {
     if (QEMU_IS_GRAPHIC_CONSOLE(con)) {
@@ -2500,20 +1548,6 @@ int qemu_console_get_height(QemuConsole *con, int fallback)
     }
 }
 
-static void vc_chr_accept_input(Chardev *chr)
-{
-    VCChardev *drv = VC_CHARDEV(chr);
-
-    kbd_send_chars(drv->console);
-}
-
-static void vc_chr_set_echo(Chardev *chr, bool echo)
-{
-    VCChardev *drv = VC_CHARDEV(chr);
-
-    drv->console->echo = echo;
-}
-
 int qemu_invalidate_text_consoles(void)
 {
     QemuConsole *s;
@@ -2531,70 +1565,6 @@ int qemu_invalidate_text_consoles(void)
     return count;
 }
 
-static void qemu_text_console_update_cursor(void *opaque)
-{
-    cursor_visible_phase = !cursor_visible_phase;
-
-    if (qemu_invalidate_text_consoles()) {
-        timer_mod(cursor_timer,
-                  qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + CONSOLE_CURSOR_PERIOD / 2);
-    }
-}
-
-static void vc_chr_open(Chardev *chr,
-                        ChardevBackend *backend,
-                        bool *be_opened,
-                        Error **errp)
-{
-    ChardevVC *vc = backend->u.vc.data;
-    VCChardev *drv = VC_CHARDEV(chr);
-    QemuTextConsole *s;
-    unsigned width = 0;
-    unsigned height = 0;
-
-    if (vc->has_width) {
-        width = vc->width;
-    } else if (vc->has_cols) {
-        width = vc->cols * FONT_WIDTH;
-    }
-
-    if (vc->has_height) {
-        height = vc->height;
-    } else if (vc->has_rows) {
-        height = vc->rows * FONT_HEIGHT;
-    }
-
-    trace_console_txt_new(width, height);
-    if (width == 0 || height == 0) {
-        s = QEMU_TEXT_CONSOLE(object_new(TYPE_QEMU_TEXT_CONSOLE));
-        width = qemu_console_get_width(NULL, 80 * FONT_WIDTH);
-        height = qemu_console_get_height(NULL, 24 * FONT_HEIGHT);
-    } else {
-        s = QEMU_TEXT_CONSOLE(object_new(TYPE_QEMU_FIXED_TEXT_CONSOLE));
-    }
-
-    dpy_gfx_replace_surface(QEMU_CONSOLE(s), qemu_create_displaysurface(width, height));
-
-    s->chr = chr;
-    drv->console = s;
-
-    /* set current text attributes to default */
-    drv->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
-    text_console_resize(s);
-
-    if (chr->label) {
-        char *msg;
-
-        drv->t_attrib.bgcol = QEMU_COLOR_BLUE;
-        msg = g_strdup_printf("%s console\r\n", chr->label);
-        qemu_chr_write(chr, (uint8_t *)msg, strlen(msg), true);
-        g_free(msg);
-        drv->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
-    }
-
-    *be_opened = true;
-}
-
 void qemu_console_resize(QemuConsole *s, int width, int height)
 {
     DisplaySurface *surface = qemu_console_surface(s);
@@ -2721,63 +1691,3 @@ void qemu_display_help(void)
         }
     }
 }
-
-static void vc_chr_parse(QemuOpts *opts, ChardevBackend *backend, Error **errp)
-{
-    int val;
-    ChardevVC *vc;
-
-    backend->type = CHARDEV_BACKEND_KIND_VC;
-    vc = backend->u.vc.data = g_new0(ChardevVC, 1);
-    qemu_chr_parse_common(opts, qapi_ChardevVC_base(vc));
-
-    val = qemu_opt_get_number(opts, "width", 0);
-    if (val != 0) {
-        vc->has_width = true;
-        vc->width = val;
-    }
-
-    val = qemu_opt_get_number(opts, "height", 0);
-    if (val != 0) {
-        vc->has_height = true;
-        vc->height = val;
-    }
-
-    val = qemu_opt_get_number(opts, "cols", 0);
-    if (val != 0) {
-        vc->has_cols = true;
-        vc->cols = val;
-    }
-
-    val = qemu_opt_get_number(opts, "rows", 0);
-    if (val != 0) {
-        vc->has_rows = true;
-        vc->rows = val;
-    }
-}
-
-static void char_vc_class_init(ObjectClass *oc, void *data)
-{
-    ChardevClass *cc = CHARDEV_CLASS(oc);
-
-    cc->parse = vc_chr_parse;
-    cc->open = vc_chr_open;
-    cc->chr_write = vc_chr_write;
-    cc->chr_accept_input = vc_chr_accept_input;
-    cc->chr_set_echo = vc_chr_set_echo;
-}
-
-static const TypeInfo char_vc_type_info = {
-    .name = TYPE_CHARDEV_VC,
-    .parent = TYPE_CHARDEV,
-    .instance_size = sizeof(VCChardev),
-    .class_init = char_vc_class_init,
-};
-
-void qemu_console_early_init(void)
-{
-    /* set the default vc driver */
-    if (!object_class_by_name(TYPE_CHARDEV_VC)) {
-        type_register(&char_vc_type_info);
-    }
-}
diff --git a/ui/meson.build b/ui/meson.build
index d81609fb0e..0a1e8272a3 100644
--- a/ui/meson.build
+++ b/ui/meson.build
@@ -6,6 +6,7 @@ system_ss.add(png)
 system_ss.add(files(
   'clipboard.c',
   'console.c',
+  'console-vc.c',
   'cursor.c',
   'input-keymap.c',
   'input-legacy.c',
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PULL 11/14] ui/console: move DisplaySurface to its own header
  2023-09-12 10:46 [PULL 00/14] Ui patches marcandre.lureau
                   ` (9 preceding siblings ...)
  2023-09-12 10:46 ` [PULL 10/14] ui/vc: split off the VC part from console.c marcandre.lureau
@ 2023-09-12 10:46 ` marcandre.lureau
  2023-09-12 10:46 ` [PULL 12/14] virtio-gpu/win32: set the destroy function on load marcandre.lureau
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: marcandre.lureau @ 2023-09-12 10:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Marc-André Lureau, Gerd Hoffmann

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Mostly for readability reasons.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
---
 include/ui/console.h | 84 +--------------------------------------
 include/ui/surface.h | 95 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 96 insertions(+), 83 deletions(-)
 create mode 100644 include/ui/surface.h

diff --git a/include/ui/console.h b/include/ui/console.h
index 93bb03a9e2..79e4702912 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -6,11 +6,7 @@
 #include "qemu/notify.h"
 #include "qapi/qapi-types-ui.h"
 #include "ui/input.h"
-
-#ifdef CONFIG_OPENGL
-# include <epoxy/gl.h>
-# include "ui/shader.h"
-#endif
+#include "ui/surface.h"
 
 #define TYPE_QEMU_CONSOLE "qemu-console"
 OBJECT_DECLARE_TYPE(QemuConsole, QemuConsoleClass, QEMU_CONSOLE)
@@ -136,9 +132,6 @@ struct QemuConsoleClass {
     ObjectClass parent_class;
 };
 
-#define QEMU_ALLOCATED_FLAG     0x01
-#define QEMU_PLACEHOLDER_FLAG   0x02
-
 typedef struct ScanoutTexture {
     uint32_t backing_id;
     bool backing_y_0_top;
@@ -151,20 +144,6 @@ typedef struct ScanoutTexture {
     void *d3d_tex2d;
 } ScanoutTexture;
 
-typedef struct DisplaySurface {
-    pixman_image_t *image;
-    uint8_t flags;
-#ifdef CONFIG_OPENGL
-    GLenum glformat;
-    GLenum gltype;
-    GLuint texture;
-#endif
-#ifdef WIN32
-    HANDLE handle;
-    uint32_t handle_offset;
-#endif
-} DisplaySurface;
-
 typedef struct QemuUIInfo {
     /* physical dimension */
     uint16_t width_mm;
@@ -344,30 +323,6 @@ struct DisplayGLCtx {
 };
 
 DisplayState *init_displaystate(void);
-DisplaySurface *qemu_create_displaysurface_from(int width, int height,
-                                                pixman_format_code_t format,
-                                                int linesize, uint8_t *data);
-DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image);
-DisplaySurface *qemu_create_placeholder_surface(int w, int h,
-                                                const char *msg);
-#ifdef WIN32
-void qemu_displaysurface_win32_set_handle(DisplaySurface *surface,
-                                          HANDLE h, uint32_t offset);
-#endif
-PixelFormat qemu_default_pixelformat(int bpp);
-
-DisplaySurface *qemu_create_displaysurface(int width, int height);
-void qemu_free_displaysurface(DisplaySurface *surface);
-
-static inline int is_buffer_shared(DisplaySurface *surface)
-{
-    return !(surface->flags & QEMU_ALLOCATED_FLAG);
-}
-
-static inline int is_placeholder(DisplaySurface *surface)
-{
-    return surface->flags & QEMU_PLACEHOLDER_FLAG;
-}
 
 void register_displaychangelistener(DisplayChangeListener *dcl);
 void update_displaychangelistener(DisplayChangeListener *dcl,
@@ -415,43 +370,6 @@ int dpy_gl_ctx_make_current(QemuConsole *con, QEMUGLContext ctx);
 
 bool console_has_gl(QemuConsole *con);
 
-static inline int surface_stride(DisplaySurface *s)
-{
-    return pixman_image_get_stride(s->image);
-}
-
-static inline void *surface_data(DisplaySurface *s)
-{
-    return pixman_image_get_data(s->image);
-}
-
-static inline int surface_width(DisplaySurface *s)
-{
-    return pixman_image_get_width(s->image);
-}
-
-static inline int surface_height(DisplaySurface *s)
-{
-    return pixman_image_get_height(s->image);
-}
-
-static inline pixman_format_code_t surface_format(DisplaySurface *s)
-{
-    return pixman_image_get_format(s->image);
-}
-
-static inline int surface_bits_per_pixel(DisplaySurface *s)
-{
-    int bits = PIXMAN_FORMAT_BPP(surface_format(s));
-    return bits;
-}
-
-static inline int surface_bytes_per_pixel(DisplaySurface *s)
-{
-    int bits = PIXMAN_FORMAT_BPP(surface_format(s));
-    return DIV_ROUND_UP(bits, 8);
-}
-
 typedef uint32_t console_ch_t;
 
 static inline void console_write_ch(console_ch_t *dest, uint32_t ch)
diff --git a/include/ui/surface.h b/include/ui/surface.h
new file mode 100644
index 0000000000..4244e0ca4a
--- /dev/null
+++ b/include/ui/surface.h
@@ -0,0 +1,95 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * QEMU UI Console
+ */
+#ifndef SURFACE_H
+#define SURFACE_H
+
+#include "ui/qemu-pixman.h"
+
+#ifdef CONFIG_OPENGL
+# include <epoxy/gl.h>
+# include "ui/shader.h"
+#endif
+
+#define QEMU_ALLOCATED_FLAG     0x01
+#define QEMU_PLACEHOLDER_FLAG   0x02
+
+typedef struct DisplaySurface {
+    pixman_image_t *image;
+    uint8_t flags;
+#ifdef CONFIG_OPENGL
+    GLenum glformat;
+    GLenum gltype;
+    GLuint texture;
+#endif
+#ifdef WIN32
+    HANDLE handle;
+    uint32_t handle_offset;
+#endif
+} DisplaySurface;
+
+PixelFormat qemu_default_pixelformat(int bpp);
+
+DisplaySurface *qemu_create_displaysurface_from(int width, int height,
+                                                pixman_format_code_t format,
+                                                int linesize, uint8_t *data);
+DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image);
+DisplaySurface *qemu_create_placeholder_surface(int w, int h,
+                                                const char *msg);
+#ifdef WIN32
+void qemu_displaysurface_win32_set_handle(DisplaySurface *surface,
+                                          HANDLE h, uint32_t offset);
+#endif
+
+DisplaySurface *qemu_create_displaysurface(int width, int height);
+void qemu_free_displaysurface(DisplaySurface *surface);
+
+static inline int is_buffer_shared(DisplaySurface *surface)
+{
+    return !(surface->flags & QEMU_ALLOCATED_FLAG);
+}
+
+static inline int is_placeholder(DisplaySurface *surface)
+{
+    return surface->flags & QEMU_PLACEHOLDER_FLAG;
+}
+
+static inline int surface_stride(DisplaySurface *s)
+{
+    return pixman_image_get_stride(s->image);
+}
+
+static inline void *surface_data(DisplaySurface *s)
+{
+    return pixman_image_get_data(s->image);
+}
+
+static inline int surface_width(DisplaySurface *s)
+{
+    return pixman_image_get_width(s->image);
+}
+
+static inline int surface_height(DisplaySurface *s)
+{
+    return pixman_image_get_height(s->image);
+}
+
+static inline pixman_format_code_t surface_format(DisplaySurface *s)
+{
+    return pixman_image_get_format(s->image);
+}
+
+static inline int surface_bits_per_pixel(DisplaySurface *s)
+{
+    int bits = PIXMAN_FORMAT_BPP(surface_format(s));
+    return bits;
+}
+
+static inline int surface_bytes_per_pixel(DisplaySurface *s)
+{
+    int bits = PIXMAN_FORMAT_BPP(surface_format(s));
+    return DIV_ROUND_UP(bits, 8);
+}
+
+#endif
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PULL 12/14] virtio-gpu/win32: set the destroy function on load
  2023-09-12 10:46 [PULL 00/14] Ui patches marcandre.lureau
                   ` (10 preceding siblings ...)
  2023-09-12 10:46 ` [PULL 11/14] ui/console: move DisplaySurface to its own header marcandre.lureau
@ 2023-09-12 10:46 ` marcandre.lureau
  2023-09-12 10:46 ` [PULL 13/14] ui: fix crash when there are no active_console marcandre.lureau
  2023-09-12 10:46 ` [PULL 14/14] ui: add precondition for dpy_get_ui_info() marcandre.lureau
  13 siblings, 0 replies; 20+ messages in thread
From: marcandre.lureau @ 2023-09-12 10:46 UTC (permalink / raw)
  To: qemu-devel
  Cc: stefanha, Marc-André Lureau, Gerd Hoffmann,
	Michael S. Tsirkin

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Don't forget to unmap the resource memory.

Fixes: commit 9462ff469 ("virtio-gpu/win32: allocate shareable 2d resources/images")

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/display/virtio-gpu.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index bbd5c6561a..93857ad523 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -1283,7 +1283,9 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
             g_free(res);
             return -EINVAL;
         }
-
+#ifdef WIN32
+        pixman_image_set_destroy_function(res->image, win32_pixman_image_destroy, res->handle);
+#endif
 
         res->addrs = g_new(uint64_t, res->iov_cnt);
         res->iov = g_new(struct iovec, res->iov_cnt);
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PULL 13/14] ui: fix crash when there are no active_console
  2023-09-12 10:46 [PULL 00/14] Ui patches marcandre.lureau
                   ` (11 preceding siblings ...)
  2023-09-12 10:46 ` [PULL 12/14] virtio-gpu/win32: set the destroy function on load marcandre.lureau
@ 2023-09-12 10:46 ` marcandre.lureau
  2023-09-12 11:00   ` Michael Tokarev
  2023-09-12 10:46 ` [PULL 14/14] ui: add precondition for dpy_get_ui_info() marcandre.lureau
  13 siblings, 1 reply; 20+ messages in thread
From: marcandre.lureau @ 2023-09-12 10:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Marc-André Lureau, Gerd Hoffmann

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Thread 1 "qemu-system-x86" received signal SIGSEGV, Segmentation fault.
0x0000555555888630 in dpy_ui_info_supported (con=0x0) at ../ui/console.c:812
812	    return con->hw_ops->ui_info != NULL;
(gdb) bt
#0  0x0000555555888630 in dpy_ui_info_supported (con=0x0) at ../ui/console.c:812
#1  0x00005555558a44b1 in protocol_client_msg (vs=0x5555578c76c0, data=0x5555581e93f0 <incomplete sequence \373>, len=24) at ../ui/vnc.c:2585
#2  0x00005555558a19ac in vnc_client_read (vs=0x5555578c76c0) at ../ui/vnc.c:1607
#3  0x00005555558a1ac2 in vnc_client_io (ioc=0x5555581eb0e0, condition=G_IO_IN, opaque=0x5555578c76c0) at ../ui/vnc.c:1635

Fixes:
https://issues.redhat.com/browse/RHEL-2600

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Albert Esteve <aesteve@redhat.com>
---
 ui/console.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/ui/console.c b/ui/console.c
index da341f08da..aa1e09462c 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -806,6 +806,9 @@ bool dpy_ui_info_supported(QemuConsole *con)
     if (con == NULL) {
         con = active_console;
     }
+    if (con == NULL) {
+        return false;
+    }
 
     return con->hw_ops->ui_info != NULL;
 }
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PULL 14/14] ui: add precondition for dpy_get_ui_info()
  2023-09-12 10:46 [PULL 00/14] Ui patches marcandre.lureau
                   ` (12 preceding siblings ...)
  2023-09-12 10:46 ` [PULL 13/14] ui: fix crash when there are no active_console marcandre.lureau
@ 2023-09-12 10:46 ` marcandre.lureau
  2023-09-14 11:52   ` Daniel P. Berrangé
  13 siblings, 1 reply; 20+ messages in thread
From: marcandre.lureau @ 2023-09-12 10:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha, Marc-André Lureau, Gerd Hoffmann

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Ensure that it only get called when dpy_ui_info_supported(). The
function should always return a result. There should be a non-null
console or active_console.

Modify the argument to be const as well.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Albert Esteve <aesteve@redhat.com>
---
 include/ui/console.h | 2 +-
 ui/console.c         | 4 +++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/include/ui/console.h b/include/ui/console.h
index 79e4702912..28882f15a5 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -329,7 +329,7 @@ void update_displaychangelistener(DisplayChangeListener *dcl,
                                   uint64_t interval);
 void unregister_displaychangelistener(DisplayChangeListener *dcl);
 
-bool dpy_ui_info_supported(QemuConsole *con);
+bool dpy_ui_info_supported(const QemuConsole *con);
 const QemuUIInfo *dpy_get_ui_info(const QemuConsole *con);
 int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info, bool delay);
 
diff --git a/ui/console.c b/ui/console.c
index aa1e09462c..4a4f19ed33 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -801,7 +801,7 @@ static void dpy_set_ui_info_timer(void *opaque)
     con->hw_ops->ui_info(con->hw, head, &con->ui_info);
 }
 
-bool dpy_ui_info_supported(QemuConsole *con)
+bool dpy_ui_info_supported(const QemuConsole *con)
 {
     if (con == NULL) {
         con = active_console;
@@ -815,6 +815,8 @@ bool dpy_ui_info_supported(QemuConsole *con)
 
 const QemuUIInfo *dpy_get_ui_info(const QemuConsole *con)
 {
+    assert(dpy_ui_info_supported(con));
+
     if (con == NULL) {
         con = active_console;
     }
-- 
2.41.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PULL 13/14] ui: fix crash when there are no active_console
  2023-09-12 10:46 ` [PULL 13/14] ui: fix crash when there are no active_console marcandre.lureau
@ 2023-09-12 11:00   ` Michael Tokarev
  2023-09-12 11:09     ` Marc-André Lureau
  2023-09-12 11:09     ` Daniel P. Berrangé
  0 siblings, 2 replies; 20+ messages in thread
From: Michael Tokarev @ 2023-09-12 11:00 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel; +Cc: stefanha, Gerd Hoffmann

12.09.2023 13:46, marcandre.lureau@redhat.com пишет:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> Thread 1 "qemu-system-x86" received signal SIGSEGV, Segmentation fault.
> 0x0000555555888630 in dpy_ui_info_supported (con=0x0) at ../ui/console.c:812
> 812	    return con->hw_ops->ui_info != NULL;
> (gdb) bt
> #0  0x0000555555888630 in dpy_ui_info_supported (con=0x0) at ../ui/console.c:812
> #1  0x00005555558a44b1 in protocol_client_msg (vs=0x5555578c76c0, data=0x5555581e93f0 <incomplete sequence \373>, len=24) at ../ui/vnc.c:2585
> #2  0x00005555558a19ac in vnc_client_read (vs=0x5555578c76c0) at ../ui/vnc.c:1607
> #3  0x00005555558a1ac2 in vnc_client_io (ioc=0x5555581eb0e0, condition=G_IO_IN, opaque=0x5555578c76c0) at ../ui/vnc.c:1635
> 
> Fixes:
> https://issues.redhat.com/browse/RHEL-2600

FWIW, this link does not work for me (requires auth).

Is there a commit which introduced this issue?

Thanks,

/mjt


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PULL 13/14] ui: fix crash when there are no active_console
  2023-09-12 11:00   ` Michael Tokarev
@ 2023-09-12 11:09     ` Marc-André Lureau
  2023-09-12 11:15       ` Daniel P. Berrangé
  2023-09-12 11:09     ` Daniel P. Berrangé
  1 sibling, 1 reply; 20+ messages in thread
From: Marc-André Lureau @ 2023-09-12 11:09 UTC (permalink / raw)
  To: Michael Tokarev; +Cc: qemu-devel, stefanha, Gerd Hoffmann

Hi

On Tue, Sep 12, 2023 at 3:01 PM Michael Tokarev <mjt@tls.msk.ru> wrote:
>
> 12.09.2023 13:46, marcandre.lureau@redhat.com пишет:
> > From: Marc-André Lureau <marcandre.lureau@redhat.com>
> >
> > Thread 1 "qemu-system-x86" received signal SIGSEGV, Segmentation fault.
> > 0x0000555555888630 in dpy_ui_info_supported (con=0x0) at ../ui/console.c:812
> > 812       return con->hw_ops->ui_info != NULL;
> > (gdb) bt
> > #0  0x0000555555888630 in dpy_ui_info_supported (con=0x0) at ../ui/console.c:812
> > #1  0x00005555558a44b1 in protocol_client_msg (vs=0x5555578c76c0, data=0x5555581e93f0 <incomplete sequence \373>, len=24) at ../ui/vnc.c:2585
> > #2  0x00005555558a19ac in vnc_client_read (vs=0x5555578c76c0) at ../ui/vnc.c:1607
> > #3  0x00005555558a1ac2 in vnc_client_io (ioc=0x5555581eb0e0, condition=G_IO_IN, opaque=0x5555578c76c0) at ../ui/vnc.c:1635
> >
> > Fixes:
> > https://issues.redhat.com/browse/RHEL-2600
>
> FWIW, this link does not work for me (requires auth).

hmm, should be ok now.

>
> Is there a commit which introduced this issue?

It was reported against v6.2 (2021). I think it was introduced with
commit 763deea7e9 ("vnc: add support for extended desktop resize"),
but it might have been reproducible earlier.

thanks


-- 
Marc-André Lureau


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PULL 13/14] ui: fix crash when there are no active_console
  2023-09-12 11:00   ` Michael Tokarev
  2023-09-12 11:09     ` Marc-André Lureau
@ 2023-09-12 11:09     ` Daniel P. Berrangé
  1 sibling, 0 replies; 20+ messages in thread
From: Daniel P. Berrangé @ 2023-09-12 11:09 UTC (permalink / raw)
  To: Michael Tokarev; +Cc: marcandre.lureau, qemu-devel, stefanha, Gerd Hoffmann

On Tue, Sep 12, 2023 at 02:00:46PM +0300, Michael Tokarev wrote:
> 12.09.2023 13:46, marcandre.lureau@redhat.com пишет:
> > From: Marc-André Lureau <marcandre.lureau@redhat.com>
> > 
> > Thread 1 "qemu-system-x86" received signal SIGSEGV, Segmentation fault.
> > 0x0000555555888630 in dpy_ui_info_supported (con=0x0) at ../ui/console.c:812
> > 812	    return con->hw_ops->ui_info != NULL;
> > (gdb) bt
> > #0  0x0000555555888630 in dpy_ui_info_supported (con=0x0) at ../ui/console.c:812
> > #1  0x00005555558a44b1 in protocol_client_msg (vs=0x5555578c76c0, data=0x5555581e93f0 <incomplete sequence \373>, len=24) at ../ui/vnc.c:2585
> > #2  0x00005555558a19ac in vnc_client_read (vs=0x5555578c76c0) at ../ui/vnc.c:1607
> > #3  0x00005555558a1ac2 in vnc_client_io (ioc=0x5555581eb0e0, condition=G_IO_IN, opaque=0x5555578c76c0) at ../ui/vnc.c:1635
> > 
> > Fixes:
> > https://issues.redhat.com/browse/RHEL-2600
> 
> FWIW, this link does not work for me (requires auth).

This particular bug is marked as Red Hat employee access only, so
should be dropped from the commit message.

FWIW, it says in terms of reproducability

Steps to reproduce
1. Boot up guest, but only add vnc device and without graphics device
/usr/libexec/qemu-kvm \
-name guest=gg \
-machine pc-q35-rhel8.6.0,kernel_irqchip=split \
-cpu host \
-m 8192 \
-smp 4,maxcpus=4,cores=2,threads=1,dies=1,sockets=2  \
-nodefaults \
-boot menu=on \
-device pcie-root-port,port=16,chassis=1,id=pci.1,bus=pcie.0,addr=0x2 \
-blockdev '\{"driver":"file","filename":"/home/kvm_autotest_root/images/rhel890-64-virtio-scsi.qcow2","node-name":"libvirt-1-storage","auto-read-only":true,"discard":"unmap"}' \
-blockdev '\{"node-name":"libvirt-1-format","read-only":false,"driver":"qcow2","file":"libvirt-1-storage","backing":null}' \
-device virtio-blk-pci,bus=pci.1,addr=0x0,drive=libvirt-1-format,id=virtio-disk0 \
-enable-kvm \
-monitor stdio \
-vnc :0 \

2. Try to connect this guest
remote-viewer vnc://10.73.210.78:5900

3. About 10 seconds to trigger qemu core dump.


The trigger appears to be the lack of any VGA device hardware
present, despite having VNC enabled.

With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PULL 13/14] ui: fix crash when there are no active_console
  2023-09-12 11:09     ` Marc-André Lureau
@ 2023-09-12 11:15       ` Daniel P. Berrangé
  0 siblings, 0 replies; 20+ messages in thread
From: Daniel P. Berrangé @ 2023-09-12 11:15 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: Michael Tokarev, qemu-devel, stefanha, Gerd Hoffmann

On Tue, Sep 12, 2023 at 03:09:29PM +0400, Marc-André Lureau wrote:
> Hi
> 
> On Tue, Sep 12, 2023 at 3:01 PM Michael Tokarev <mjt@tls.msk.ru> wrote:
> >
> > 12.09.2023 13:46, marcandre.lureau@redhat.com пишет:
> > > From: Marc-André Lureau <marcandre.lureau@redhat.com>
> > >
> > > Thread 1 "qemu-system-x86" received signal SIGSEGV, Segmentation fault.
> > > 0x0000555555888630 in dpy_ui_info_supported (con=0x0) at ../ui/console.c:812
> > > 812       return con->hw_ops->ui_info != NULL;
> > > (gdb) bt
> > > #0  0x0000555555888630 in dpy_ui_info_supported (con=0x0) at ../ui/console.c:812
> > > #1  0x00005555558a44b1 in protocol_client_msg (vs=0x5555578c76c0, data=0x5555581e93f0 <incomplete sequence \373>, len=24) at ../ui/vnc.c:2585
> > > #2  0x00005555558a19ac in vnc_client_read (vs=0x5555578c76c0) at ../ui/vnc.c:1607
> > > #3  0x00005555558a1ac2 in vnc_client_io (ioc=0x5555581eb0e0, condition=G_IO_IN, opaque=0x5555578c76c0) at ../ui/vnc.c:1635
> > >
> > > Fixes:
> > > https://issues.redhat.com/browse/RHEL-2600
> >
> > FWIW, this link does not work for me (requires auth).
> 
> hmm, should be ok now.
> 
> >
> > Is there a commit which introduced this issue?
> 
> It was reported against v6.2 (2021). I think it was introduced with
> commit 763deea7e9 ("vnc: add support for extended desktop resize"),
> but it might have been reproducible earlier.

Since its in a release, this probably ought to be tagged as a (denial
of service) CVE, since it enables a remote VNC client to crash the
whole VM. Fortunately it is only triggerable /after/ authentication
so the severity is relatively low.

With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PULL 14/14] ui: add precondition for dpy_get_ui_info()
  2023-09-12 10:46 ` [PULL 14/14] ui: add precondition for dpy_get_ui_info() marcandre.lureau
@ 2023-09-14 11:52   ` Daniel P. Berrangé
  0 siblings, 0 replies; 20+ messages in thread
From: Daniel P. Berrangé @ 2023-09-14 11:52 UTC (permalink / raw)
  To: marcandre.lureau; +Cc: qemu-devel, stefanha, Gerd Hoffmann

On Tue, Sep 12, 2023 at 02:46:48PM +0400, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> Ensure that it only get called when dpy_ui_info_supported(). The
> function should always return a result. There should be a non-null
> console or active_console.

Empirically that does not appear to be the case. After this patch,
a no-args QEMU launch immediately aborts:

$ ./build/qemu-system-x86_64 
qemu-system-x86_64: ../ui/console.c:818: dpy_get_ui_info: Assertion `dpy_ui_info_supported(con)' failed.
Aborted (core dumped)

This ought to be running the GTK UI for me. Manually ask for
SDL instead and it doesn't crash.

> 
> Modify the argument to be const as well.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> Reviewed-by: Albert Esteve <aesteve@redhat.com>
> ---
>  include/ui/console.h | 2 +-
>  ui/console.c         | 4 +++-
>  2 files changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/include/ui/console.h b/include/ui/console.h
> index 79e4702912..28882f15a5 100644
> --- a/include/ui/console.h
> +++ b/include/ui/console.h
> @@ -329,7 +329,7 @@ void update_displaychangelistener(DisplayChangeListener *dcl,
>                                    uint64_t interval);
>  void unregister_displaychangelistener(DisplayChangeListener *dcl);
>  
> -bool dpy_ui_info_supported(QemuConsole *con);
> +bool dpy_ui_info_supported(const QemuConsole *con);
>  const QemuUIInfo *dpy_get_ui_info(const QemuConsole *con);
>  int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info, bool delay);
>  
> diff --git a/ui/console.c b/ui/console.c
> index aa1e09462c..4a4f19ed33 100644
> --- a/ui/console.c
> +++ b/ui/console.c
> @@ -801,7 +801,7 @@ static void dpy_set_ui_info_timer(void *opaque)
>      con->hw_ops->ui_info(con->hw, head, &con->ui_info);
>  }
>  
> -bool dpy_ui_info_supported(QemuConsole *con)
> +bool dpy_ui_info_supported(const QemuConsole *con)
>  {
>      if (con == NULL) {
>          con = active_console;
> @@ -815,6 +815,8 @@ bool dpy_ui_info_supported(QemuConsole *con)
>  
>  const QemuUIInfo *dpy_get_ui_info(const QemuConsole *con)
>  {
> +    assert(dpy_ui_info_supported(con));
> +
>      if (con == NULL) {
>          con = active_console;
>      }
> -- 
> 2.41.0
> 
> 

With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|



^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2023-09-14 11:52 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-09-12 10:46 [PULL 00/14] Ui patches marcandre.lureau
2023-09-12 10:46 ` [PULL 01/14] docs: vhost-user-gpu: add protocol changes for dmabuf modifiers marcandre.lureau
2023-09-12 10:46 ` [PULL 02/14] contrib/vhost-user-gpu: add support for sending " marcandre.lureau
2023-09-12 10:46 ` [PULL 03/14] vhost-user-gpu: support " marcandre.lureau
2023-09-12 10:46 ` [PULL 04/14] vmmouse: replace DPRINTF with tracing marcandre.lureau
2023-09-12 10:46 ` [PULL 05/14] vmmouse: use explicit code marcandre.lureau
2023-09-12 10:46 ` [PULL 06/14] ui/vc: remove kbd_put_keysym() and update function calls marcandre.lureau
2023-09-12 10:46 ` [PULL 07/14] ui/vc: rename kbd_put to qemu_text_console functions marcandre.lureau
2023-09-12 10:46 ` [PULL 08/14] ui/console: remove redundant format field marcandre.lureau
2023-09-12 10:46 ` [PULL 09/14] ui/vc: preliminary QemuTextConsole changes before split marcandre.lureau
2023-09-12 10:46 ` [PULL 10/14] ui/vc: split off the VC part from console.c marcandre.lureau
2023-09-12 10:46 ` [PULL 11/14] ui/console: move DisplaySurface to its own header marcandre.lureau
2023-09-12 10:46 ` [PULL 12/14] virtio-gpu/win32: set the destroy function on load marcandre.lureau
2023-09-12 10:46 ` [PULL 13/14] ui: fix crash when there are no active_console marcandre.lureau
2023-09-12 11:00   ` Michael Tokarev
2023-09-12 11:09     ` Marc-André Lureau
2023-09-12 11:15       ` Daniel P. Berrangé
2023-09-12 11:09     ` Daniel P. Berrangé
2023-09-12 10:46 ` [PULL 14/14] ui: add precondition for dpy_get_ui_info() marcandre.lureau
2023-09-14 11:52   ` Daniel P. Berrangé

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).