On 9/28/26 3:28 PM, Maximilian Immanuel Brandtner wrote: > On Mon, 2026-09-28 at 09:32 -0400, Jason J. Herne wrote: >> >> >> On 9/28/26 5:08 AM, Maximilian Immanuel Brandtner wrote: >>> Add a tty code to indicate a resize frame. The body contains two >>> big >>> endian 16-bit integers rows and columns. >>> >>> After reset, the guest must be informed of the terminal size again. >>> A >>> chardev that doesn't report its size yields 0x0, which shouldn't >>> replace >>> the guest's default. >>> >>> Signed-off-by: Maximilian Immanuel Brandtner <[email protected]> >>> --- >>> Changelog: >>> v2: >>> - Use packed struct and named event type codes for resize frames >>> - Trigger initial resize event in console_reset() instead of >>> console_init(), skip when chardev reports no size >>> - Reset event_pending after resize event >>> >>> Requires the following pre-req: >>> [PATCH v7 00/12] virtio-console: notify about the terminal >>> size >>> >>> (https://lore.kernel.org/qemu-devel/20260609-console-resize-v7-0-0c >>> [email protected]/) >>> >>> Testing: >>> - Tested on QEMU: commit 38879a667f with the following patches >>> applied: >>> [PATCH v7 00/12] virtio-console: notify about the terminal >>> size >>> - Tested on linux-next (commit c1f49dea2b8f) with the following >>> patches >>> applied: >>> [PATCH 0/2] s390/sclp: Resize for sclp-vt220 console >>> --- >>> hw/char/sclpconsole.c | 92 +++++++++++++++++++++++++++++++++++++- >>> ----- >>> 1 file changed, 80 insertions(+), 12 deletions(-) >>> >>> diff --git a/hw/char/sclpconsole.c b/hw/char/sclpconsole.c >>> index 179d12745c..12033e1e46 100644 >>> --- a/hw/char/sclpconsole.c >>> +++ b/hw/char/sclpconsole.c >>> @@ -33,6 +33,9 @@ typedef struct ASCIIConsoleData { >>> /* max size for ASCII data in 4K SCCB page */ >>> #define SIZE_BUFFER_VT220 4080 >>> >>> +#define SCLP_CONSOLE_EVENT_TYPE_DATA 0x00 >>> +#define SCLP_CONSOLE_EVENT_TYPE_RESIZE 0x08 >>> + >>> struct SCLPConsole { >>> SCLPEvent event; >>> CharFrontend chr; >>> @@ -42,6 +45,8 @@ struct SCLPConsole { >>> uint32_t iov_data_len; /* length of byte stream in >>> buffer */ >>> uint32_t iov_sclp_rest; /* length of byte stream not read via >>> SCLP */ >>> bool notify; /* qemu_notify_event() req'd if >>> true */ >>> + bool resize; >>> + bool resize_init; >>> }; >>> typedef struct SCLPConsole SCLPConsole; >>> >>> @@ -49,6 +54,12 @@ typedef struct SCLPConsole SCLPConsole; >>> DECLARE_INSTANCE_CHECKER(SCLPConsole, SCLP_CONSOLE, >>> TYPE_SCLP_CONSOLE) >>> >>> +typedef struct SCLPConsoleResizeData { >>> + uint8_t type; >>> + uint16_t rows; >>> + uint16_t cols; >>> +} QEMU_PACKED SCLPConsoleResizeData; >>> + >>> /* character layer call-back functions */ >>> >>> /* Return number of bytes that fit into iov buffer */ >>> @@ -81,6 +92,29 @@ static void chr_read(void *opaque, const uint8_t >>> *buf, int size) >>> sclp_service_interrupt(0); >>> } >>> >>> +static void chr_event(void *opaque, QEMUChrEvent event) >>> +{ >>> + SCLPConsole *scon = opaque; >>> + >>> + assert(scon); >>> + >>> + switch (event) { >>> + case CHR_EVENT_RESIZE: >>> + case CHR_EVENT_MUX_IN: >>> + scon->resize = true; >>> + scon->resize_init = false; >>> + scon->event.event_pending = true; >>> + sclp_service_interrupt(0); >>> + break; >>> + case CHR_EVENT_BREAK: >>> + case CHR_EVENT_OPENED: >>> + case CHR_EVENT_MUX_OUT: >>> + case CHR_EVENT_CLOSED: >>> + /* ignore */ >>> + break; >>> + } >>> +} >>> + >>> /* functions to be called by event facility */ >>> >>> static bool can_handle_event(uint8_t type) >>> @@ -104,10 +138,37 @@ static sccb_mask_t receive_mask(void) >>> static void get_console_data(SCLPEvent *event, uint8_t *buf, >>> size_t *size, >>> int avail) >>> { >>> + SCLPConsoleResizeData resize_data; >>> SCLPConsole *cons = SCLP_CONSOLE(event); >>> + uint16_t rows, cols; >>> + >>> + if (cons->resize) { >>> + if (avail < sizeof(resize_data)) { >>> + *size = 0; >>> + return; >>> + } >>> >>> - /* first byte is hex 0 saying an ascii string follows */ >>> - *buf++ = '\0'; >>> + qemu_chr_fe_get_winsize(&cons->chr, &cols, &rows); >>> + >>> + if (cons->resize_init && cols == 0 && rows == 0) { >>> + *size = 0; >>> + } else { >>> + resize_data.type = SCLP_CONSOLE_EVENT_TYPE_RESIZE; >>> + resize_data.rows = cpu_to_be16(rows); >>> + resize_data.cols = cpu_to_be16(cols); >>> + >>> + memcpy(buf, &resize_data, sizeof(resize_data)); >>> + *size = sizeof(resize_data); >>> + } >>> + >>> + cons->resize = false; >>> + cons->resize_init = false; >>> + event->event_pending = cons->iov_sclp_rest != 0; >>> + >>> + return; >>> + } >>> + >>> + *buf++ = SCLP_CONSOLE_EVENT_TYPE_DATA; >>> avail--; >>> /* if all data fit into provided SCLP buffer */ >>> if (avail >= cons->iov_sclp_rest) { >>> @@ -150,6 +211,9 @@ static int read_event_data(SCLPEvent *event, >>> EventBufferHeader *evt_buf_hdr, >>> to = (uint8_t *)&acd->data; >>> avail = *slen - sizeof(ASCIIConsoleData); >>> get_console_data(event, to, &src_len, avail); >>> + if (src_len == 0) { >>> + return 0; >>> + } >>> acd->ebh.length = cpu_to_be16(sizeof(ASCIIConsoleData) + >>> src_len); >>> acd->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA; >>> @@ -233,22 +297,26 @@ static int console_init(SCLPEvent *event) >>> } >>> console_available = true; >>> qemu_chr_fe_set_handlers(&scon->chr, chr_can_read, >>> - chr_read, NULL, NULL, scon, NULL, >>> true); >>> + chr_read, chr_event, NULL, scon, >>> NULL, true); >>> >>> return 0; >>> } >>> >>> static void console_reset(DeviceState *dev) >>> { >>> - SCLPEvent *event = SCLP_EVENT(dev); >>> - SCLPConsole *scon = SCLP_CONSOLE(event); >>> - >>> - event->event_pending = false; >>> - scon->iov_sclp = 0; >>> - scon->iov_bs = 0; >>> - scon->iov_data_len = 0; >>> - scon->iov_sclp_rest = 0; >>> - scon->notify = false; >>> + SCLPEvent *event = SCLP_EVENT(dev); >>> + SCLPConsole *scon = SCLP_CONSOLE(event); >>> + >>> + scon->iov_sclp = 0; >>> + scon->iov_bs = 0; >>> + scon->iov_data_len = 0; >>> + scon->iov_sclp_rest = 0; >>> + scon->notify = false; >>> + >>> + /* the guest defaults its terminal size on reset, announce the >>> real one */ >>> + scon->resize = true; >>> + scon->resize_init = true; >>> + event->event_pending = true; >>> } >> >> This is a style fix, included in a functional patch. I suppose it is >> probably borderline, but it might be best to put this in its own >> patch. > > I thought about that, but concluded that a 6-line indentation commit > would be too small to warrant its own patch. If you'd prefer it to be > split I could also send it as a seperate patch.
I would prefer it in its own patch if possible as a preparatory commit prior to this one. It keeps git blame easier to read if we have issues later and are trying to sort out where the functional changes occurred vs what was just whitespace cleanup. With the whitespace changes broken out: Reviewed-by: Matthew Rosato <[email protected]>
