@samitouri / QOSamiQemu / commits / 16f4408ba1

hw/char/pl011: support backend hotswap

Currently, when Incus issues "chardev-change" QMP command to change chardev backend from ringbuf to socket it receives an error (with aarch64 VM): "Chardev user does not support chardev hotswap" [1], [2] Let's fix this by properly implementing BackendChangeHandler for pl011. Please, note that we have to "replay" CHR_IOCTL_SERIAL_SET_BREAK, because if BRK bit was set before backend change (i.e. (s->lcr & LCR_BRK) is true), then after change we need to send break to a new backend too. Link: https://discuss.linuxcontainers.org/t/unable-to-connect-to-vm-console-on-arm-architecture/23096/3 [1] Link: https://github.com/lxc/distrobuilder/issues/892 [2] Reported-by: Stéphane Graber <stgraber@stgraber.org> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io> Message-id: 20260821104832.151452-1-alexander@mihalicyn.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

Alexander Mikhalitsyn committed Aug 21, 2026 at 12:48 UTC 16f4408ba1f9d1a66a0652d1c0cdc7e1cae688e6
1 file changed +26 -5
hw/char/pl011.c
+26 -5
@@ -425,6 +425,11 @@ static void pl011_loopback_break(PL011State *s, int brk_enable)
425 }
426 }
427
428 +static inline void pl011_set_break(PL011State *s, int brk_enable)
429 +{
430 + qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_BREAK, &brk_enable);
431 +}
432 +
433 static void pl011_write(void *opaque, hwaddr offset,
434 uint64_t value, unsigned size)
435 {
@@ -462,9 +467,8 @@ static void pl011_write(void *opaque, hwaddr offset,
467 pl011_reset_tx_fifo(s);
468 }
469 if ((s->lcr ^ value) & LCR_BRK) {
465 - int break_enable = value & LCR_BRK;
466 - qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
467 - &break_enable);
470 + bool break_enable = value & LCR_BRK;
471 + pl011_set_break(s, break_enable);
472 pl011_loopback_break(s, break_enable);
473 }
474 s->lcr = value;
@@ -660,12 +664,29 @@ static void pl011_init(Object *obj)
664 s->id = pl011_id_arm;
665 }
666
667 +static int pl011_be_change(void *opaque);
668 +
669 +static inline void pl011_set_handlers(PL011State *s)
670 +{
671 + qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive,
672 + pl011_event, pl011_be_change, s, NULL, true);
673 +}
674 +
675 +static int pl011_be_change(void *opaque)
676 +{
677 + PL011State *s = opaque;
678 +
679 + pl011_set_handlers(s);
680 + pl011_set_break(s, s->lcr & LCR_BRK);
681 +
682 + return 0;
683 +}
684 +
685 static void pl011_realize(DeviceState *dev, Error **errp)
686 {
687 PL011State *s = PL011(dev);
688
667 - qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive,
668 - pl011_event, NULL, s, NULL, true);
689 + pl011_set_handlers(s);
690 }
691
692 static void pl011_reset(DeviceState *dev)