If a virtio serial port is a console port forward terminal resize messages from the chardev backend to the guest.
Signed-off-by: Szymon Lukasz <noh4...@gmail.com> --- hw/char/virtio-console.c | 64 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/hw/char/virtio-console.c b/hw/char/virtio-console.c index 97b9240ef5..1ea06aad08 100644 --- a/hw/char/virtio-console.c +++ b/hw/char/virtio-console.c @@ -29,6 +29,7 @@ typedef struct VirtConsole { CharBackend chr; guint watch; + uint16_t cols, rows; } VirtConsole; /* @@ -104,6 +105,36 @@ static ssize_t flush_buf(VirtIOSerialPort *port, return ret; } +static void virtconsole_send_resize(VirtIOSerialPort *port) +{ + uint16_t cols, rows; + VirtConsole *vcon = VIRTIO_CONSOLE(port); + + /* + * We probably shouldn't send these messages before + * we told the guest it is a console port (which we do + * by sending VIRTIO_CONSOLE_CONSOLE_PORT message). + * Instead of adding a new field to the device state + * lets just use the guest_connected field for that purpose + * since the guest should not care about the terminal size + * before opening the port. + */ + if (!port->guest_connected) { + return; + } + + if (qemu_chr_fe_get_winsize(&vcon->chr, &cols, &rows) < 0) { + cols = 0; + rows = 0; + } + + if (cols != vcon->cols || rows != vcon->rows) { + vcon->cols = cols; + vcon->rows = rows; + virtio_serial_send_console_resize(port, cols, rows); + } +} + /* Callback function that's called when the guest opens/closes the port */ static void set_guest_connected(VirtIOSerialPort *port, int guest_connected) { @@ -111,7 +142,9 @@ static void set_guest_connected(VirtIOSerialPort *port, int guest_connected) DeviceState *dev = DEVICE(port); VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port); - if (!k->is_console) { + if (k->is_console) { + virtconsole_send_resize(port); + } else { qemu_chr_fe_set_open(&vcon->chr, guest_connected); } @@ -171,6 +204,22 @@ static void chr_event(void *opaque, QEMUChrEvent event) } } +static void chr_event_console(void *opaque, QEMUChrEvent event) +{ + VirtConsole *vcon = opaque; + VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(vcon); + + switch (event) { + case CHR_EVENT_OPENED: + case CHR_EVENT_RESIZE: + trace_virtio_console_chr_event(port->id, event); + virtconsole_send_resize(port); + break; + default: + break; + } +} + static int chr_be_change(void *opaque) { VirtConsole *vcon = opaque; @@ -179,7 +228,9 @@ static int chr_be_change(void *opaque) if (k->is_console) { qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read, - NULL, chr_be_change, vcon, NULL, true); + chr_event_console, chr_be_change, + vcon, NULL, true); + virtconsole_send_resize(port); } else { qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read, chr_event, chr_be_change, vcon, NULL, false); @@ -207,7 +258,7 @@ static void virtconsole_enable_backend(VirtIOSerialPort *port, bool enable) VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port); qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read, - k->is_console ? NULL : chr_event, + k->is_console ? chr_event_console : chr_event, chr_be_change, vcon, NULL, false); } else { qemu_chr_fe_set_handlers(&vcon->chr, NULL, NULL, NULL, @@ -227,6 +278,11 @@ static void virtconsole_realize(DeviceState *dev, Error **errp) return; } + if (k->is_console) { + vcon->cols = (uint16_t) -1; + vcon->rows = (uint16_t) -1; + } + if (qemu_chr_fe_backend_connected(&vcon->chr)) { /* * For consoles we don't block guest data transfer just @@ -239,7 +295,7 @@ static void virtconsole_realize(DeviceState *dev, Error **errp) */ if (k->is_console) { qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read, - NULL, chr_be_change, + chr_event_console, chr_be_change, vcon, NULL, true); virtio_serial_open(port); } else { -- 2.27.0