diff --git a/SOURCES/kvm-char-change-qemu_chr_fe_add_watch-to-return-unsigned.patch b/SOURCES/kvm-char-change-qemu_chr_fe_add_watch-to-return-unsigned.patch new file mode 100644 index 0000000..87f18bf --- /dev/null +++ b/SOURCES/kvm-char-change-qemu_chr_fe_add_watch-to-return-unsigned.patch @@ -0,0 +1,106 @@ +From 357b8e45c81e79a1547f65ea4109b0882050b1e9 Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Tue, 23 May 2017 14:15:10 +0200 +Subject: [PATCH] char: change qemu_chr_fe_add_watch to return unsigned + +RH-Author: Eduardo Habkost +Message-id: <20170523141510.24762-1-ehabkost@redhat.com> +Patchwork-id: 75397 +O-Subject: [RHEL-7.3.z qemu-kvm PATCH] char: change qemu_chr_fe_add_watch to return unsigned +Bugzilla: 1452332 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Miroslav Rezanina + +From: Paolo Bonzini + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1452332 +Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=13257135 + +g_source_attach can return any value between 1 and UINT_MAX if you let +QEMU run long enough. However, qemu_chr_fe_add_watch can also return +a negative errno value when the device is disconnected or does not +support chr_add_watch. Change it to return zero to avoid overloading +these values. + +Fix the cadence_uart which asserts in this case (easily obtained with +"-serial pty"). + +Backport notes: + + This is the same patch submitted to the 7.4 branch. + +7.4 backport conflicts: + hw/char/cadence_uart.c (no qemu_chr_fe_add_watch() call) + net/vhost-user.c (doesn't exit) + qemu-char.c (trivial conflict) + +Tested-by: Bret Ketchum +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Paolo Bonzini +(cherry picked from commit 6f1de6b70d857d5e316ae6fd908f52818b827b08) +Signed-off-by: Eduardo Habkost +Signed-off-by: Miroslav Rezanina +--- + include/sysemu/char.h | 16 ++++++++++++++-- + qemu-char.c | 8 ++++---- + 2 files changed, 18 insertions(+), 6 deletions(-) + +diff --git a/include/sysemu/char.h b/include/sysemu/char.h +index ad101d9..c0e5b25 100644 +--- a/include/sysemu/char.h ++++ b/include/sysemu/char.h +@@ -147,8 +147,20 @@ void qemu_chr_fe_set_open(struct CharDriverState *chr, int fe_open); + void qemu_chr_fe_printf(CharDriverState *s, const char *fmt, ...) + GCC_FMT_ATTR(2, 3); + +-int qemu_chr_fe_add_watch(CharDriverState *s, GIOCondition cond, +- GIOFunc func, void *user_data); ++/** ++ * @qemu_chr_fe_add_watch: ++ * ++ * If the backend is connected, create and add a #GSource that fires ++ * when the given condition (typically G_IO_OUT|G_IO_HUP or G_IO_HUP) ++ * is active; return the #GSource's tag. If it is disconnected, ++ * return 0. ++ * ++ * @cond the condition to poll for ++ * @func the function to call when the condition happens ++ * @user_data the opaque pointer to pass to @func ++ */ ++guint qemu_chr_fe_add_watch(CharDriverState *s, GIOCondition cond, ++ GIOFunc func, void *user_data); + + /** + * @qemu_chr_fe_write: +diff --git a/qemu-char.c b/qemu-char.c +index 08cb959..5edca0a 100644 +--- a/qemu-char.c ++++ b/qemu-char.c +@@ -3373,19 +3373,19 @@ void qemu_chr_fe_set_open(struct CharDriverState *chr, int fe_open) + } + } + +-int qemu_chr_fe_add_watch(CharDriverState *s, GIOCondition cond, +- GIOFunc func, void *user_data) ++guint qemu_chr_fe_add_watch(CharDriverState *s, GIOCondition cond, ++ GIOFunc func, void *user_data) + { + GSource *src; + guint tag; + + if (s->chr_add_watch == NULL) { +- return -ENOSYS; ++ return 0; + } + + src = s->chr_add_watch(s, cond); + if (!src) { +- return -EINVAL; ++ return 0; + } + + g_source_set_callback(src, (GSourceFunc)func, user_data, NULL); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-char-serial-Fix-emptyness-check.patch b/SOURCES/kvm-char-serial-Fix-emptyness-check.patch new file mode 100644 index 0000000..7b571ce --- /dev/null +++ b/SOURCES/kvm-char-serial-Fix-emptyness-check.patch @@ -0,0 +1,46 @@ +From c9b0af3739fc5b79a20bf2492b5e8c1dea055dc0 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 19 May 2017 00:35:10 +0200 +Subject: [PATCH 05/18] char/serial: Fix emptyness check + +RH-Author: Fam Zheng +Message-id: <20170519003523.21163-6-famz@redhat.com> +Patchwork-id: 75361 +O-Subject: [RHEL-7.3.z qemu-kvm PATCH 05/18] char/serial: Fix emptyness check +Bugzilla: 1452332 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Laurent Vivier +RH-Acked-by: Eduardo Habkost + +From: Peter Crosthwaite + +This was guarding against a full fifo rather than an empty fifo when +popping. Fix. + +Signed-off-by: Peter Crosthwaite +Reviewed-by: Martin Kletzander +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Michael Tokarev +(cherry picked from commit 88c1ee73d3231c74ff90bcfc084a7589670ec244) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + hw/char/serial.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/char/serial.c b/hw/char/serial.c +index 3345de1..489a885 100644 +--- a/hw/char/serial.c ++++ b/hw/char/serial.c +@@ -225,7 +225,7 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque) + + if (s->tsr_retry <= 0) { + if (s->fcr & UART_FCR_FE) { +- s->tsr = fifo8_is_full(&s->xmit_fifo) ? ++ s->tsr = fifo8_is_empty(&s->xmit_fifo) ? + 0 : fifo8_pop(&s->xmit_fifo); + if (!s->xmit_fifo.num) { + s->lsr |= UART_LSR_THRE; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-char-serial-Fix-emptyness-handling.patch b/SOURCES/kvm-char-serial-Fix-emptyness-handling.patch new file mode 100644 index 0000000..966d2f5 --- /dev/null +++ b/SOURCES/kvm-char-serial-Fix-emptyness-handling.patch @@ -0,0 +1,54 @@ +From a14715c6b64f4764259028923a9c04ae7844c546 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 19 May 2017 00:35:11 +0200 +Subject: [PATCH 06/18] char/serial: Fix emptyness handling + +RH-Author: Fam Zheng +Message-id: <20170519003523.21163-7-famz@redhat.com> +Patchwork-id: 75359 +O-Subject: [RHEL-7.3.z qemu-kvm PATCH 06/18] char/serial: Fix emptyness handling +Bugzilla: 1452332 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Laurent Vivier +RH-Acked-by: Eduardo Habkost + +From: Don Slutz + +The commit 88c1ee73d3231c74ff90bcfc084a7589670ec244 +char/serial: Fix emptyness check + +Still causes extra NULL byte(s) to be sent. + +So if the fifo is empty, do not send an extra NULL byte. + +Reviewed-by: Peter Crosthwaite +Signed-off-by: Don Slutz +Message-id: 1395160174-16006-1-git-send-email-dslutz@verizon.com +Signed-off-by: Peter Maydell +(cherry picked from commit dffacd4654ec8bf2898aed230852154c6ed755ed) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + hw/char/serial.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/hw/char/serial.c b/hw/char/serial.c +index 489a885..e020b0e 100644 +--- a/hw/char/serial.c ++++ b/hw/char/serial.c +@@ -225,8 +225,10 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque) + + if (s->tsr_retry <= 0) { + if (s->fcr & UART_FCR_FE) { +- s->tsr = fifo8_is_empty(&s->xmit_fifo) ? +- 0 : fifo8_pop(&s->xmit_fifo); ++ if (fifo8_is_empty(&s->xmit_fifo)) { ++ return FALSE; ++ } ++ s->tsr = fifo8_pop(&s->xmit_fifo); + if (!s->xmit_fifo.num) { + s->lsr |= UART_LSR_THRE; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-char-serial-Use-generic-Fifo8.patch b/SOURCES/kvm-char-serial-Use-generic-Fifo8.patch new file mode 100644 index 0000000..ed8c9d1 --- /dev/null +++ b/SOURCES/kvm-char-serial-Use-generic-Fifo8.patch @@ -0,0 +1,290 @@ +From 462caff619f890c56194ac50b70b095c26cd133e Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 19 May 2017 00:35:07 +0200 +Subject: [PATCH 02/18] char/serial: Use generic Fifo8 + +RH-Author: Fam Zheng +Message-id: <20170519003523.21163-3-famz@redhat.com> +Patchwork-id: 75358 +O-Subject: [RHEL-7.3.z qemu-kvm PATCH 02/18] char/serial: Use generic Fifo8 +Bugzilla: 1452332 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Laurent Vivier +RH-Acked-by: Eduardo Habkost + +From: Peter Crosthwaite + +Use the generic Fifo8 helper provided by QEMU, rather than re-implement +privately. + +Signed-off-by: Peter Crosthwaite +Signed-off-by: Michael Tokarev +(cherry picked from commit 8e8638fa87ff045f5dadec7342301bf10de776ff) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina + +Conflicts: + hw/char/serial.c +Conflict because in downstream we've got 4df7961faa out of order. +--- + hw/char/serial.c | 98 +++++++++++++++++------------------------------- + include/hw/char/serial.h | 15 +++----- + 2 files changed, 39 insertions(+), 74 deletions(-) + +diff --git a/hw/char/serial.c b/hw/char/serial.c +index 7866b0f..0d4450e 100644 +--- a/hw/char/serial.c ++++ b/hw/char/serial.c +@@ -93,8 +93,6 @@ + #define UART_FCR_RFR 0x02 /* RCVR Fifo Reset */ + #define UART_FCR_FE 0x01 /* FIFO Enable */ + +-#define XMIT_FIFO 0 +-#define RECV_FIFO 1 + #define MAX_XMIT_RETRY 4 + + #ifdef DEBUG_SERIAL +@@ -107,50 +105,14 @@ do {} while (0) + + static void serial_receive1(void *opaque, const uint8_t *buf, int size); + +-static void fifo_clear(SerialState *s, int fifo) ++static inline void recv_fifo_put(SerialState *s, uint8_t chr) + { +- SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo; +- memset(f->data, 0, UART_FIFO_LENGTH); +- f->count = 0; +- f->head = 0; +- f->tail = 0; +-} +- +-static int fifo_put(SerialState *s, int fifo, uint8_t chr) +-{ +- SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo; +- + /* Receive overruns do not overwrite FIFO contents. */ +- if (fifo == XMIT_FIFO || f->count < UART_FIFO_LENGTH) { +- +- f->data[f->head++] = chr; +- +- if (f->head == UART_FIFO_LENGTH) +- f->head = 0; +- } +- +- if (f->count < UART_FIFO_LENGTH) +- f->count++; +- else if (fifo == RECV_FIFO) ++ if (!fifo8_is_full(&s->recv_fifo)) { ++ fifo8_push(&s->recv_fifo, chr); ++ } else { + s->lsr |= UART_LSR_OE; +- +- return 1; +-} +- +-static uint8_t fifo_get(SerialState *s, int fifo) +-{ +- SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo; +- uint8_t c; +- +- if(f->count == 0) +- return 0; +- +- c = f->data[f->tail++]; +- if (f->tail == UART_FIFO_LENGTH) +- f->tail = 0; +- f->count--; +- +- return c; ++ } + } + + static void serial_update_irq(SerialState *s) +@@ -166,7 +128,7 @@ static void serial_update_irq(SerialState *s) + tmp_iir = UART_IIR_CTI; + } else if ((s->ier & UART_IER_RDI) && (s->lsr & UART_LSR_DR) && + (!(s->fcr & UART_FCR_FE) || +- s->recv_fifo.count >= s->recv_fifo.itl)) { ++ s->recv_fifo.num >= s->recv_fifo_itl)) { + tmp_iir = UART_IIR_RDI; + } else if ((s->ier & UART_IER_THRI) && s->thr_ipending) { + tmp_iir = UART_IIR_THRI; +@@ -263,8 +225,9 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque) + + if (s->tsr_retry <= 0) { + if (s->fcr & UART_FCR_FE) { +- s->tsr = fifo_get(s,XMIT_FIFO); +- if (!s->xmit_fifo.count) { ++ s->tsr = fifo8_is_full(&s->xmit_fifo) ? ++ 0 : fifo8_pop(&s->xmit_fifo); ++ if (!s->xmit_fifo.num) { + s->lsr |= UART_LSR_THRE; + } + } else if ((s->lsr & UART_LSR_THRE)) { +@@ -318,7 +281,11 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, + } else { + s->thr = (uint8_t) val; + if(s->fcr & UART_FCR_FE) { +- fifo_put(s, XMIT_FIFO, s->thr); ++ /* xmit overruns overwrite data, so make space if needed */ ++ if (fifo8_is_full(&s->xmit_fifo)) { ++ fifo8_pop(&s->xmit_fifo); ++ } ++ fifo8_push(&s->xmit_fifo, s->thr); + s->thr_ipending = 0; + s->lsr &= ~UART_LSR_TEMT; + s->lsr &= ~UART_LSR_THRE; +@@ -369,28 +336,28 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, + if (val & UART_FCR_RFR) { + qemu_del_timer(s->fifo_timeout_timer); + s->timeout_ipending=0; +- fifo_clear(s,RECV_FIFO); ++ fifo8_reset(&s->recv_fifo); + } + + if (val & UART_FCR_XFR) { +- fifo_clear(s,XMIT_FIFO); ++ fifo8_reset(&s->xmit_fifo); + } + + if (val & UART_FCR_FE) { + s->iir |= UART_IIR_FE; +- /* Set RECV_FIFO trigger Level */ ++ /* Set recv_fifo trigger Level */ + switch (val & 0xC0) { + case UART_FCR_ITL_1: +- s->recv_fifo.itl = 1; ++ s->recv_fifo_itl = 1; + break; + case UART_FCR_ITL_2: +- s->recv_fifo.itl = 4; ++ s->recv_fifo_itl = 4; + break; + case UART_FCR_ITL_3: +- s->recv_fifo.itl = 8; ++ s->recv_fifo_itl = 8; + break; + case UART_FCR_ITL_4: +- s->recv_fifo.itl = 14; ++ s->recv_fifo_itl = 14; + break; + } + } else +@@ -462,8 +429,9 @@ static uint64_t serial_ioport_read(void *opaque, hwaddr addr, unsigned size) + ret = s->divider & 0xff; + } else { + if(s->fcr & UART_FCR_FE) { +- ret = fifo_get(s,RECV_FIFO); +- if (s->recv_fifo.count == 0) { ++ ret = fifo8_is_full(&s->recv_fifo) ? ++ 0 : fifo8_pop(&s->recv_fifo); ++ if (s->recv_fifo.num == 0) { + s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); + } else { + qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock_ns (vm_clock) + s->char_transmit_time * 4); +@@ -537,7 +505,7 @@ static uint64_t serial_ioport_read(void *opaque, hwaddr addr, unsigned size) + static int serial_can_receive(SerialState *s) + { + if(s->fcr & UART_FCR_FE) { +- if (s->recv_fifo.count < UART_FIFO_LENGTH) { ++ if (s->recv_fifo.num < UART_FIFO_LENGTH) { + /* + * Advertise (fifo.itl - fifo.count) bytes when count < ITL, and 1 + * if above. If UART_FIFO_LENGTH - fifo.count is advertised the +@@ -545,8 +513,8 @@ static int serial_can_receive(SerialState *s) + * the guest has a chance to respond, effectively overriding the ITL + * that the guest has set. + */ +- return (s->recv_fifo.count <= s->recv_fifo.itl) ? +- s->recv_fifo.itl - s->recv_fifo.count : 1; ++ return (s->recv_fifo.num <= s->recv_fifo_itl) ? ++ s->recv_fifo_itl - s->recv_fifo.num : 1; + } else { + return 0; + } +@@ -559,7 +527,7 @@ static void serial_receive_break(SerialState *s) + { + s->rbr = 0; + /* When the LSR_DR is set a null byte is pushed into the fifo */ +- fifo_put(s, RECV_FIFO, '\0'); ++ recv_fifo_put(s, '\0'); + s->lsr |= UART_LSR_BI | UART_LSR_DR; + serial_update_irq(s); + } +@@ -567,7 +535,7 @@ static void serial_receive_break(SerialState *s) + /* There's data in recv_fifo and s->rbr has not been read for 4 char transmit times */ + static void fifo_timeout_int (void *opaque) { + SerialState *s = opaque; +- if (s->recv_fifo.count) { ++ if (s->recv_fifo.num) { + s->timeout_ipending = 1; + serial_update_irq(s); + } +@@ -589,7 +557,7 @@ static void serial_receive1(void *opaque, const uint8_t *buf, int size) + if(s->fcr & UART_FCR_FE) { + int i; + for (i = 0; i < size; i++) { +- fifo_put(s, RECV_FIFO, buf[i]); ++ recv_fifo_put(s, buf[i]); + } + s->lsr |= UART_LSR_DR; + /* call the timeout receive callback in 4 char transmit time */ +@@ -669,8 +637,8 @@ static void serial_reset(void *opaque) + s->char_transmit_time = (get_ticks_per_sec() / 9600) * 10; + s->poll_msl = 0; + +- fifo_clear(s,RECV_FIFO); +- fifo_clear(s,XMIT_FIFO); ++ fifo8_reset(&s->recv_fifo); ++ fifo8_reset(&s->xmit_fifo); + + s->last_xmit_ts = qemu_get_clock_ns(vm_clock); + +@@ -693,6 +661,8 @@ void serial_init_core(SerialState *s) + + qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1, + serial_event, s); ++ fifo8_create(&s->recv_fifo, UART_FIFO_LENGTH); ++ fifo8_create(&s->xmit_fifo, UART_FIFO_LENGTH); + serial_reset(s); + } + +diff --git a/include/hw/char/serial.h b/include/hw/char/serial.h +index bca79f1..9ab81f6 100644 +--- a/include/hw/char/serial.h ++++ b/include/hw/char/serial.h +@@ -28,17 +28,10 @@ + #include "hw/hw.h" + #include "sysemu/sysemu.h" + #include "exec/memory.h" ++#include "qemu/fifo8.h" + + #define UART_FIFO_LENGTH 16 /* 16550A Fifo Length */ + +-typedef struct SerialFIFO { +- uint8_t data[UART_FIFO_LENGTH]; +- uint8_t count; +- uint8_t itl; /* Interrupt Trigger Level */ +- uint8_t tail; +- uint8_t head; +-} SerialFIFO; +- + struct SerialState { + uint16_t divider; + uint8_t rbr; /* receive register */ +@@ -67,8 +60,10 @@ struct SerialState { + + /* Time when the last byte was successfully sent out of the tsr */ + uint64_t last_xmit_ts; +- SerialFIFO recv_fifo; +- SerialFIFO xmit_fifo; ++ Fifo8 recv_fifo; ++ Fifo8 xmit_fifo; ++ /* Interrupt trigger level for recv_fifo */ ++ uint8_t recv_fifo_itl; + + struct QEMUTimer *fifo_timeout_timer; + int timeout_ipending; /* timeout interrupt pending state */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-char-serial-cosmetic-fixes.patch b/SOURCES/kvm-char-serial-cosmetic-fixes.patch new file mode 100644 index 0000000..2f9e776 --- /dev/null +++ b/SOURCES/kvm-char-serial-cosmetic-fixes.patch @@ -0,0 +1,95 @@ +From f3c1372702f7cac6d8b405cf8c51e15eabc7c054 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 19 May 2017 00:35:06 +0200 +Subject: [PATCH 01/18] char/serial: cosmetic fixes. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Fam Zheng +Message-id: <20170519003523.21163-2-famz@redhat.com> +Patchwork-id: 75356 +O-Subject: [RHEL-7.3.z qemu-kvm PATCH 01/18] char/serial: cosmetic fixes. +Bugzilla: 1452332 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Laurent Vivier +RH-Acked-by: Eduardo Habkost + +From: Peter Crosthwaite + +Some cosmetic fixes to char/serial fixing some checkpatch errors. + +Cc: qemu-trivial@nongnu.org + +Signed-off-by: Peter Crosthwaite +Reviewed-by: Andreas Färber +Signed-off-by: Michael Tokarev +(cherry picked from commit 7f4f0a227fe0b24c35d0898f9ae7d5909fb51137) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + hw/char/serial.c | 30 +++++++++++++++++++----------- + 1 file changed, 19 insertions(+), 11 deletions(-) + +diff --git a/hw/char/serial.c b/hw/char/serial.c +index 2383c31..7866b0f 100644 +--- a/hw/char/serial.c ++++ b/hw/char/serial.c +@@ -264,8 +264,9 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque) + if (s->tsr_retry <= 0) { + if (s->fcr & UART_FCR_FE) { + s->tsr = fifo_get(s,XMIT_FIFO); +- if (!s->xmit_fifo.count) ++ if (!s->xmit_fifo.count) { + s->lsr |= UART_LSR_THRE; ++ } + } else if ((s->lsr & UART_LSR_THRE)) { + return FALSE; + } else { +@@ -462,10 +463,11 @@ static uint64_t serial_ioport_read(void *opaque, hwaddr addr, unsigned size) + } else { + if(s->fcr & UART_FCR_FE) { + ret = fifo_get(s,RECV_FIFO); +- if (s->recv_fifo.count == 0) ++ if (s->recv_fifo.count == 0) { + s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); +- else ++ } else { + qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock_ns (vm_clock) + s->char_transmit_time * 4); ++ } + s->timeout_ipending = 0; + } else { + ret = s->rbr; +@@ -535,15 +537,21 @@ static uint64_t serial_ioport_read(void *opaque, hwaddr addr, unsigned size) + static int serial_can_receive(SerialState *s) + { + if(s->fcr & UART_FCR_FE) { +- if(s->recv_fifo.count < UART_FIFO_LENGTH) +- /* Advertise (fifo.itl - fifo.count) bytes when count < ITL, and 1 if above. If UART_FIFO_LENGTH - fifo.count is +- advertised the effect will be to almost always fill the fifo completely before the guest has a chance to respond, +- effectively overriding the ITL that the guest has set. */ +- return (s->recv_fifo.count <= s->recv_fifo.itl) ? s->recv_fifo.itl - s->recv_fifo.count : 1; +- else +- return 0; ++ if (s->recv_fifo.count < UART_FIFO_LENGTH) { ++ /* ++ * Advertise (fifo.itl - fifo.count) bytes when count < ITL, and 1 ++ * if above. If UART_FIFO_LENGTH - fifo.count is advertised the ++ * effect will be to almost always fill the fifo completely before ++ * the guest has a chance to respond, effectively overriding the ITL ++ * that the guest has set. ++ */ ++ return (s->recv_fifo.count <= s->recv_fifo.itl) ? ++ s->recv_fifo.itl - s->recv_fifo.count : 1; ++ } else { ++ return 0; ++ } + } else { +- return !(s->lsr & UART_LSR_DR); ++ return !(s->lsr & UART_LSR_DR); + } + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-char-serial-fix-copy-paste-error-fifo8_is_full-vs-em.patch b/SOURCES/kvm-char-serial-fix-copy-paste-error-fifo8_is_full-vs-em.patch new file mode 100644 index 0000000..35577f6 --- /dev/null +++ b/SOURCES/kvm-char-serial-fix-copy-paste-error-fifo8_is_full-vs-em.patch @@ -0,0 +1,46 @@ +From a04a0d4cf131163600ebede71d223d9d01a32511 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 19 May 2017 00:35:09 +0200 +Subject: [PATCH 04/18] char/serial: fix copy&paste error (fifo8_is_full vs + empty) + +RH-Author: Fam Zheng +Message-id: <20170519003523.21163-5-famz@redhat.com> +Patchwork-id: 75360 +O-Subject: [RHEL-7.3.z qemu-kvm PATCH 04/18] char/serial: fix copy&paste error (fifo8_is_full vs empty) +Bugzilla: 1452332 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Laurent Vivier +RH-Acked-by: Eduardo Habkost + +From: Vladimir Senkov + +Copy&paste error in serial.c causes a crash when attempting +to read from UART (if there is no data to be read) + +Signed-off-by: Vladimir Senkov +Reviewed-by: Peter Crosthwaite +Signed-off-by: Michael Tokarev +(cherry picked from commit b165b0d8e62bb65a02d7670d75ebb77a9280bde1) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + hw/char/serial.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/char/serial.c b/hw/char/serial.c +index 72112cc..3345de1 100644 +--- a/hw/char/serial.c ++++ b/hw/char/serial.c +@@ -425,7 +425,7 @@ static uint64_t serial_ioport_read(void *opaque, hwaddr addr, unsigned size) + ret = s->divider & 0xff; + } else { + if(s->fcr & UART_FCR_FE) { +- ret = fifo8_is_full(&s->recv_fifo) ? ++ ret = fifo8_is_empty(&s->recv_fifo) ? + 0 : fifo8_pop(&s->recv_fifo); + if (s->recv_fifo.num == 0) { + s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-char-serial-serial_ioport_write-Factor-out-common-co.patch b/SOURCES/kvm-char-serial-serial_ioport_write-Factor-out-common-co.patch new file mode 100644 index 0000000..3970777 --- /dev/null +++ b/SOURCES/kvm-char-serial-serial_ioport_write-Factor-out-common-co.patch @@ -0,0 +1,62 @@ +From 5114efc4a077a1fdfa9873e6f44a00d5f8101f65 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 19 May 2017 00:35:08 +0200 +Subject: [PATCH 03/18] char/serial: serial_ioport_write: Factor out common + code +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Fam Zheng +Message-id: <20170519003523.21163-4-famz@redhat.com> +Patchwork-id: 75357 +O-Subject: [RHEL-7.3.z qemu-kvm PATCH 03/18] char/serial: serial_ioport_write: Factor out common code +Bugzilla: 1452332 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Laurent Vivier +RH-Acked-by: Eduardo Habkost + +From: Peter Crosthwaite + +These three lines are common to both FIFO and regular mode. Just factor +them out to outside the if rather than replicate the same lines inside +both if and else. + +Cc: qemu-trivial@nongnu.org + +Signed-off-by: Peter Crosthwaite +Reviewed-by: Andreas Färber +Signed-off-by: Michael Tokarev +(cherry picked from commit b5601df7624b461759651c49ac72a189951780b9) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + hw/char/serial.c | 10 +++------- + 1 file changed, 3 insertions(+), 7 deletions(-) + +diff --git a/hw/char/serial.c b/hw/char/serial.c +index 0d4450e..72112cc 100644 +--- a/hw/char/serial.c ++++ b/hw/char/serial.c +@@ -286,15 +286,11 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, + fifo8_pop(&s->xmit_fifo); + } + fifo8_push(&s->xmit_fifo, s->thr); +- s->thr_ipending = 0; + s->lsr &= ~UART_LSR_TEMT; +- s->lsr &= ~UART_LSR_THRE; +- serial_update_irq(s); +- } else { +- s->thr_ipending = 0; +- s->lsr &= ~UART_LSR_THRE; +- serial_update_irq(s); + } ++ s->thr_ipending = 0; ++ s->lsr &= ~UART_LSR_THRE; ++ serial_update_irq(s); + serial_xmit(NULL, G_IO_OUT, s); + } + break; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-char-ignore-flow-control-if-a-PTY-s-slave-is-no.patch b/SOURCES/kvm-qemu-char-ignore-flow-control-if-a-PTY-s-slave-is-no.patch new file mode 100644 index 0000000..6463982 --- /dev/null +++ b/SOURCES/kvm-qemu-char-ignore-flow-control-if-a-PTY-s-slave-is-no.patch @@ -0,0 +1,61 @@ +From 1e2929d890fb4cc88162b9771ed93b1c61f89b33 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 19 May 2017 00:35:14 +0200 +Subject: [PATCH 09/18] qemu-char: ignore flow control if a PTY's slave is not + connected + +RH-Author: Fam Zheng +Message-id: <20170519003523.21163-10-famz@redhat.com> +Patchwork-id: 75364 +O-Subject: [RHEL-7.3.z qemu-kvm PATCH 09/18] qemu-char: ignore flow control if a PTY's slave is not connected +Bugzilla: 1452332 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Laurent Vivier +RH-Acked-by: Eduardo Habkost + +From: Paolo Bonzini + +After commit f702e62 (serial: change retry logic to avoid concurrency, +2014-07-11), guest boot hangs if the backend is an unconnected PTY. + +The reason is that PTYs do not support G_IO_HUP, and serial_xmit is +never called. To fix this, simply invoke serial_xmit immediately +(via g_idle_source_new) when this happens. + +Tested-by: Pavel Hrdina +Signed-off-by: Paolo Bonzini +(cherry picked from commit 62c339c5272ce8fbe8ca52695cee8ff40da7872e) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + qemu-char.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/qemu-char.c b/qemu-char.c +index 47ac55a..08cb959 100644 +--- a/qemu-char.c ++++ b/qemu-char.c +@@ -1068,6 +1068,9 @@ static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len) + static GSource *pty_chr_add_watch(CharDriverState *chr, GIOCondition cond) + { + PtyCharDriver *s = chr->opaque; ++ if (!s->connected) { ++ return NULL; ++ } + return g_io_create_watch(s->fd, cond); + } + +@@ -3381,6 +3384,10 @@ int qemu_chr_fe_add_watch(CharDriverState *s, GIOCondition cond, + } + + src = s->chr_add_watch(s, cond); ++ if (!src) { ++ return -EINVAL; ++ } ++ + g_source_set_callback(src, (GSourceFunc)func, user_data, NULL); + tag = g_source_attach(src, NULL); + g_source_unref(src); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-serial-change-retry-logic-to-avoid-concurrency.patch b/SOURCES/kvm-serial-change-retry-logic-to-avoid-concurrency.patch new file mode 100644 index 0000000..df1f0e6 --- /dev/null +++ b/SOURCES/kvm-serial-change-retry-logic-to-avoid-concurrency.patch @@ -0,0 +1,143 @@ +From 3ddb1809fc188f9aca337b19a81b40da5b992057 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 19 May 2017 00:35:13 +0200 +Subject: [PATCH 08/18] serial: change retry logic to avoid concurrency + +RH-Author: Fam Zheng +Message-id: <20170519003523.21163-9-famz@redhat.com> +Patchwork-id: 75362 +O-Subject: [RHEL-7.3.z qemu-kvm PATCH 08/18] serial: change retry logic to avoid concurrency +Bugzilla: 1452332 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Laurent Vivier +RH-Acked-by: Eduardo Habkost + +From: Kirill Batuzov + +Whenever serial_xmit fails to transmit a byte it adds a watch that would +call it again when the "line" becomes ready. This results in a retry +chain: + serial_xmit -> add_watch -> serial_xmit +Each chain is able to transmit one character, and for every character +passed to serial by the guest driver a new chain is spawned. + +The problem lays with the fact that a new chain is spawned even when +there is one already waiting on the watch. So there can be several retry +chains waiting concurrently on one "line". Every chain tries to transmit +current character, so character order is not messed up. But also every +chain increases retry counter (tsr_retry). If there are enough +concurrent chains this counter will hit MAX_XMIT_RETRY value and +the character will be dropped. + +To reproduce this bug you need to feed serial output to some program +consuming it slowly enough. A python script from bug #1335444 +description is an example of such program. + +This commit changes retry logic in the following way to avoid +concurrency: instead of spawning a new chain for each character being +transmitted spawn only one and make it transmit characters until FIFO is +empty. + +The change consists of two parts: + - add a do {} while () loop in serial_xmit (diff is a bit erratic + for this part, diff -w will show actual change), + - do not call serial_xmit from serial_ioport_write if there is one + waiting on the watch already. + +This should fix another issue causing bug #1335444. + +Signed-off-by: Kirill Batuzov +Signed-off-by: Paolo Bonzini +(cherry picked from commit f702e62a193e9ddb41cef95068717e5582b39a64) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + hw/char/serial.c | 59 +++++++++++++++++++++++++++++++------------------------- + 1 file changed, 33 insertions(+), 26 deletions(-) + +diff --git a/hw/char/serial.c b/hw/char/serial.c +index add4738..33e06fb 100644 +--- a/hw/char/serial.c ++++ b/hw/char/serial.c +@@ -223,37 +223,42 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque) + { + SerialState *s = opaque; + +- if (s->tsr_retry <= 0) { +- if (s->fcr & UART_FCR_FE) { +- if (fifo8_is_empty(&s->xmit_fifo)) { ++ do { ++ if (s->tsr_retry <= 0) { ++ if (s->fcr & UART_FCR_FE) { ++ if (fifo8_is_empty(&s->xmit_fifo)) { ++ return FALSE; ++ } ++ s->tsr = fifo8_pop(&s->xmit_fifo); ++ if (!s->xmit_fifo.num) { ++ s->lsr |= UART_LSR_THRE; ++ } ++ } else if ((s->lsr & UART_LSR_THRE)) { + return FALSE; +- } +- s->tsr = fifo8_pop(&s->xmit_fifo); +- if (!s->xmit_fifo.num) { ++ } else { ++ s->tsr = s->thr; + s->lsr |= UART_LSR_THRE; ++ s->lsr &= ~UART_LSR_TEMT; + } +- } else if ((s->lsr & UART_LSR_THRE)) { +- return FALSE; +- } else { +- s->tsr = s->thr; +- s->lsr |= UART_LSR_THRE; +- s->lsr &= ~UART_LSR_TEMT; + } +- } + +- if (s->mcr & UART_MCR_LOOP) { +- /* in loopback mode, say that we just received a char */ +- serial_receive1(s, &s->tsr, 1); +- } else if (qemu_chr_fe_write(s->chr, &s->tsr, 1) != 1) { +- if (s->tsr_retry >= 0 && s->tsr_retry < MAX_XMIT_RETRY && +- qemu_chr_fe_add_watch(s->chr, G_IO_OUT|G_IO_HUP, serial_xmit, s) > 0) { +- s->tsr_retry++; +- return FALSE; ++ if (s->mcr & UART_MCR_LOOP) { ++ /* in loopback mode, say that we just received a char */ ++ serial_receive1(s, &s->tsr, 1); ++ } else if (qemu_chr_fe_write(s->chr, &s->tsr, 1) != 1) { ++ if (s->tsr_retry >= 0 && s->tsr_retry < MAX_XMIT_RETRY && ++ qemu_chr_fe_add_watch(s->chr, G_IO_OUT|G_IO_HUP, ++ serial_xmit, s) > 0) { ++ s->tsr_retry++; ++ return FALSE; ++ } ++ s->tsr_retry = 0; ++ } else { ++ s->tsr_retry = 0; + } +- s->tsr_retry = 0; +- } else { +- s->tsr_retry = 0; +- } ++ /* Transmit another byte if it is already available. It is only ++ possible when FIFO is enabled and not empty. */ ++ } while ((s->fcr & UART_FCR_FE) && !fifo8_is_empty(&s->xmit_fifo)); + + s->last_xmit_ts = qemu_get_clock_ns(vm_clock); + +@@ -293,7 +298,9 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, + s->thr_ipending = 0; + s->lsr &= ~UART_LSR_THRE; + serial_update_irq(s); +- serial_xmit(NULL, G_IO_OUT, s); ++ if (s->tsr_retry <= 0) { ++ serial_xmit(NULL, G_IO_OUT, s); ++ } + } + break; + case 1: +-- +1.8.3.1 + diff --git a/SOURCES/kvm-serial-check-if-backed-by-a-physical-serial-port-at-.patch b/SOURCES/kvm-serial-check-if-backed-by-a-physical-serial-port-at-.patch new file mode 100644 index 0000000..733d5ba --- /dev/null +++ b/SOURCES/kvm-serial-check-if-backed-by-a-physical-serial-port-at-.patch @@ -0,0 +1,63 @@ +From 1882bb1a0967e7d513b0d5bd060fa214bc44efcb Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 19 May 2017 00:35:15 +0200 +Subject: [PATCH 10/18] serial: check if backed by a physical serial port at + realize time + +RH-Author: Fam Zheng +Message-id: <20170519003523.21163-11-famz@redhat.com> +Patchwork-id: 75366 +O-Subject: [RHEL-7.3.z qemu-kvm PATCH 10/18] serial: check if backed by a physical serial port at realize time +Bugzilla: 1452332 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Laurent Vivier +RH-Acked-by: Eduardo Habkost + +From: Paolo Bonzini + +Right now, s->poll_msl may linger at "0" value for an arbitrarily long +time, until serial_update_msl is called for the first time. This is +unnecessary, and will lead to the s->poll_msl field being unnecessarily +migrated. + +We can call serial_update_msl immediately at realize time (via +serial_reset) and be done with it. The memory-mapped UART was already +doing that, but not the ISA and PCI variants. + +Regarding the delta bits, be consistent with what serial_reset does when +the serial port is not backed by a physical serial port, and always clear +them at reset time. + +Signed-off-by: Paolo Bonzini +(cherry picked from commit a30cf8760f4a59797fc060c3c5a13b7749551d0c) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + hw/char/serial.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/hw/char/serial.c b/hw/char/serial.c +index 33e06fb..5ef9b95 100644 +--- a/hw/char/serial.c ++++ b/hw/char/serial.c +@@ -650,6 +650,9 @@ static void serial_reset(void *opaque) + s->thr_ipending = 0; + s->last_break_enable = 0; + qemu_irq_lower(s->irq); ++ ++ serial_update_msl(s); ++ s->msr &= ~UART_MSR_ANY_DELTA; + } + + void serial_init_core(SerialState *s) +@@ -768,7 +771,5 @@ SerialState *serial_mm_init(MemoryRegion *address_space, + memory_region_init_io(&s->io, &serial_mm_ops[end], s, + "serial", 8 << it_shift); + memory_region_add_subregion(address_space, base, &s->io); +- +- serial_update_msl(s); + return s; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-serial-clean-up-THRE-TEMT-handling.patch b/SOURCES/kvm-serial-clean-up-THRE-TEMT-handling.patch new file mode 100644 index 0000000..18e9b50 --- /dev/null +++ b/SOURCES/kvm-serial-clean-up-THRE-TEMT-handling.patch @@ -0,0 +1,125 @@ +From 9afba2b1b9f8c2af3165fb0d9b68888996fe2330 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 19 May 2017 00:35:17 +0200 +Subject: [PATCH 12/18] serial: clean up THRE/TEMT handling + +RH-Author: Fam Zheng +Message-id: <20170519003523.21163-13-famz@redhat.com> +Patchwork-id: 75367 +O-Subject: [RHEL-7.3.z qemu-kvm PATCH 12/18] serial: clean up THRE/TEMT handling +Bugzilla: 1452332 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Laurent Vivier +RH-Acked-by: Eduardo Habkost + +From: Paolo Bonzini + +- assert TEMT is cleared before sending a character; we'll get one from +TSR if tsr_retry > 0, from the FIFO or THR otherwise + +- assert THRE cleared and FIFO not empty (if enabled) before fetching a +character to send. This effectively reverts dffacd46, but the check +makes no sense and commit f702e62 (serial: change retry logic to avoid +concurrency, 2014-07-11) must have made it unnecessary. The commit +message for f702e62 talks about multiple calls to qemu_chr_fe_add_watch +triggering s->tsr_retry >= MAX_XMIT_RETRY, but other failures were +possible. For example, if you have multiple calls, the subsequent ones +will see s->tsr_retry == 0 and will find THRE and/or TEMT on entry. + +- for clarity, raise THRI immediately after the code sets THRE + +- check THRE to see if another character has to be sent. This makes +the assertions more obvious and also means TEMT has to be set as soon as +the loop ends. It makes the loop send both TSR and THR if flow-control +happens in non-FIFO mode. Previously, THR would be lost. + +- clear TEMT together with THRE even in the non-FIFO case + +The last two items are bugfixes, but they were just found by inspection +and do not squash known bugs. + +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Paolo Bonzini +(cherry picked from commit 0d931d706266d6ada3bf22d3afca1afdc8d12fa9) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina + +Conflicts: + hw/char/serial.c + +Contextual conflict because upstream has the new timer API +qemu_clock_get_ns, but downstream still uses qemu_get_clock_ns. +--- + hw/char/serial.c | 26 ++++++++++++-------------- + 1 file changed, 12 insertions(+), 14 deletions(-) + +diff --git a/hw/char/serial.c b/hw/char/serial.c +index 15c628f..c2be4bd 100644 +--- a/hw/char/serial.c ++++ b/hw/char/serial.c +@@ -224,21 +224,23 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque) + SerialState *s = opaque; + + do { ++ assert(!(s->lsr & UART_LSR_TEMT)); + if (s->tsr_retry <= 0) { ++ assert(!(s->lsr & UART_LSR_THRE)); ++ + if (s->fcr & UART_FCR_FE) { +- if (fifo8_is_empty(&s->xmit_fifo)) { +- return FALSE; +- } ++ assert(!fifo8_is_empty(&s->xmit_fifo)); + s->tsr = fifo8_pop(&s->xmit_fifo); + if (!s->xmit_fifo.num) { + s->lsr |= UART_LSR_THRE; + } +- } else if ((s->lsr & UART_LSR_THRE)) { +- return FALSE; + } else { + s->tsr = s->thr; + s->lsr |= UART_LSR_THRE; +- s->lsr &= ~UART_LSR_TEMT; ++ } ++ if ((s->lsr & UART_LSR_THRE) && !s->thr_ipending) { ++ s->thr_ipending = 1; ++ serial_update_irq(s); + } + } + +@@ -256,17 +258,13 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque) + } else { + s->tsr_retry = 0; + } ++ + /* Transmit another byte if it is already available. It is only + possible when FIFO is enabled and not empty. */ +- } while ((s->fcr & UART_FCR_FE) && !fifo8_is_empty(&s->xmit_fifo)); ++ } while (!(s->lsr & UART_LSR_THRE)); + + s->last_xmit_ts = qemu_get_clock_ns(vm_clock); +- +- if (s->lsr & UART_LSR_THRE) { +- s->lsr |= UART_LSR_TEMT; +- s->thr_ipending = 1; +- serial_update_irq(s); +- } ++ s->lsr |= UART_LSR_TEMT; + + return FALSE; + } +@@ -293,10 +291,10 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, + fifo8_pop(&s->xmit_fifo); + } + fifo8_push(&s->xmit_fifo, s->thr); +- s->lsr &= ~UART_LSR_TEMT; + } + s->thr_ipending = 0; + s->lsr &= ~UART_LSR_THRE; ++ s->lsr &= ~UART_LSR_TEMT; + serial_update_irq(s); + if (s->tsr_retry <= 0) { + serial_xmit(NULL, G_IO_OUT, s); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-serial-make-tsr_retry-unsigned.patch b/SOURCES/kvm-serial-make-tsr_retry-unsigned.patch new file mode 100644 index 0000000..85fc949 --- /dev/null +++ b/SOURCES/kvm-serial-make-tsr_retry-unsigned.patch @@ -0,0 +1,97 @@ +From fece1f0b57a8daa08e04338baab90202d75766ec Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 19 May 2017 00:35:20 +0200 +Subject: [PATCH 15/18] serial: make tsr_retry unsigned + +RH-Author: Fam Zheng +Message-id: <20170519003523.21163-16-famz@redhat.com> +Patchwork-id: 75371 +O-Subject: [RHEL-7.3.z qemu-kvm PATCH 15/18] serial: make tsr_retry unsigned +Bugzilla: 1452332 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Laurent Vivier +RH-Acked-by: Eduardo Habkost + +From: Paolo Bonzini + +It can never become negative; reflect this in the type of the field +and simplify the conditions. + +Tested-by: Bret Ketchum +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Paolo Bonzini +(cherry picked from commit 807464d8a7326e1025a2f392bf41636b0809d6da) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina + +Conflicts: + hw/char/serial.c + +Downstream doesn't have 7385b275d9, so dropped the vmstate_serial_tsr +hunk because the structure doesn't exist. + +The serial_post_load hunk is backported because it's safe, and good for +the future backport of 7385b275d9 if there will be. +--- + hw/char/serial.c | 10 +++++++--- + include/hw/char/serial.h | 2 +- + 2 files changed, 8 insertions(+), 4 deletions(-) + +diff --git a/hw/char/serial.c b/hw/char/serial.c +index 9986adf..afa1932 100644 +--- a/hw/char/serial.c ++++ b/hw/char/serial.c +@@ -225,7 +225,7 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque) + + do { + assert(!(s->lsr & UART_LSR_TEMT)); +- if (s->tsr_retry <= 0) { ++ if (s->tsr_retry == 0) { + assert(!(s->lsr & UART_LSR_THRE)); + + if (s->fcr & UART_FCR_FE) { +@@ -248,7 +248,7 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque) + /* in loopback mode, say that we just received a char */ + serial_receive1(s, &s->tsr, 1); + } else if (qemu_chr_fe_write(s->chr, &s->tsr, 1) != 1) { +- if (s->tsr_retry >= 0 && s->tsr_retry < MAX_XMIT_RETRY && ++ if (s->tsr_retry < MAX_XMIT_RETRY && + qemu_chr_fe_add_watch(s->chr, G_IO_OUT|G_IO_HUP, + serial_xmit, s) > 0) { + s->tsr_retry++; +@@ -296,7 +296,7 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, + s->lsr &= ~UART_LSR_THRE; + s->lsr &= ~UART_LSR_TEMT; + serial_update_irq(s); +- if (s->tsr_retry <= 0) { ++ if (s->tsr_retry == 0) { + serial_xmit(NULL, G_IO_OUT, s); + } + } +@@ -619,6 +619,10 @@ static int serial_post_load(void *opaque, int version_id) + if (version_id < 3) { + s->fcr_vmstate = 0; + } ++ if (s->tsr_retry > MAX_XMIT_RETRY) { ++ s->tsr_retry = MAX_XMIT_RETRY; ++ } ++ + /* Initialize fcr via setter to perform essential side-effects */ + serial_ioport_write(s, 0x02, s->fcr_vmstate, 1); + serial_update_parameters(s); +diff --git a/include/hw/char/serial.h b/include/hw/char/serial.h +index 9ab81f6..2661f8c 100644 +--- a/include/hw/char/serial.h ++++ b/include/hw/char/serial.h +@@ -55,7 +55,7 @@ struct SerialState { + int last_break_enable; + int it_shift; + int baudbase; +- int tsr_retry; ++ uint32_t tsr_retry; + uint32_t wakeup; + + /* Time when the last byte was successfully sent out of the tsr */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-serial-only-resample-THR-interrupt-on-rising-edge-of.patch b/SOURCES/kvm-serial-only-resample-THR-interrupt-on-rising-edge-of.patch new file mode 100644 index 0000000..2e30ae8 --- /dev/null +++ b/SOURCES/kvm-serial-only-resample-THR-interrupt-on-rising-edge-of.patch @@ -0,0 +1,87 @@ +From 95388b9e0745ca0125012f050c53f651811b5189 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 19 May 2017 00:35:19 +0200 +Subject: [PATCH 14/18] serial: only resample THR interrupt on rising edge of + IER.THRI + +RH-Author: Fam Zheng +Message-id: <20170519003523.21163-15-famz@redhat.com> +Patchwork-id: 75370 +O-Subject: [RHEL-7.3.z qemu-kvm PATCH 14/18] serial: only resample THR interrupt on rising edge of IER.THRI +Bugzilla: 1452332 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Laurent Vivier +RH-Acked-by: Eduardo Habkost + +From: Paolo Bonzini + +There is disagreement on whether LSR.THRE should be resampled when +IER.THRI goes from 1 to 1. Bochs only does it if IER.THRI goes from 0 +to 1; PCE does it even if IER.THRI is unchanged. But the Windows driver +seems to always go from 1 to 0 and back to 1, so do things in agreement +with Bochs, because the handling of thr_ipending was reported in 2010 +(https://lists.gnu.org/archive/html/qemu-devel/2010-03/msg01914.html) +as breaking DR-DOS Plus. + +Reported-by: Roy Tam +Signed-off-by: Paolo Bonzini +(cherry picked from commit 1645b8eee558ffe2389a081bf61d08a864c36d2c) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + hw/char/serial.c | 25 ++++++++++++++++--------- + 1 file changed, 16 insertions(+), 9 deletions(-) + +diff --git a/hw/char/serial.c b/hw/char/serial.c +index e0d29a8..9986adf 100644 +--- a/hw/char/serial.c ++++ b/hw/char/serial.c +@@ -306,10 +306,12 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, + s->divider = (s->divider & 0x00ff) | (val << 8); + serial_update_parameters(s); + } else { ++ uint8_t changed = (s->ier ^ val) & 0x0f; + s->ier = val & 0x0f; + /* If the backend device is a real serial port, turn polling of the modem +- status lines on physical port on or off depending on UART_IER_MSI state */ +- if (s->poll_msl >= 0) { ++ * status lines on physical port on or off depending on UART_IER_MSI state. ++ */ ++ if ((changed & UART_IER_MSI) && s->poll_msl >= 0) { + if (s->ier & UART_IER_MSI) { + s->poll_msl = 1; + serial_update_msl(s); +@@ -324,18 +326,23 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, + * This is not in the datasheet, but Windows relies on it. It is + * unclear if THRE has to be resampled every time THRI becomes + * 1, or only on the rising edge. Bochs does the latter, and Windows +- * always toggles IER to all zeroes and back to all ones. But for +- * now leave it as it has always been in QEMU. ++ * always toggles IER to all zeroes and back to all ones, so do the ++ * same. + * + * If IER.THRI is zero, thr_ipending is not used. Set it to zero + * so that the thr_ipending subsection is not migrated. + */ +- if ((s->ier & UART_IER_THRI) && (s->lsr & UART_LSR_THRE)) { +- s->thr_ipending = 1; +- } else { +- s->thr_ipending = 0; ++ if (changed & UART_IER_THRI) { ++ if ((s->ier & UART_IER_THRI) && (s->lsr & UART_LSR_THRE)) { ++ s->thr_ipending = 1; ++ } else { ++ s->thr_ipending = 0; ++ } ++ } ++ ++ if (changed) { ++ serial_update_irq(s); + } +- serial_update_irq(s); + } + break; + case 2: +-- +1.8.3.1 + diff --git a/SOURCES/kvm-serial-poll-the-serial-console-with-G_IO_HUP.patch b/SOURCES/kvm-serial-poll-the-serial-console-with-G_IO_HUP.patch new file mode 100644 index 0000000..ae0367b --- /dev/null +++ b/SOURCES/kvm-serial-poll-the-serial-console-with-G_IO_HUP.patch @@ -0,0 +1,124 @@ +From 3ca9dc028e21f6e66e4ad21d6b2948e23691d2ae Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 19 May 2017 00:35:12 +0200 +Subject: [PATCH 07/18] serial: poll the serial console with G_IO_HUP +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Fam Zheng +Message-id: <20170519003523.21163-8-famz@redhat.com> +Patchwork-id: 75363 +O-Subject: [RHEL-7.3.z qemu-kvm PATCH 07/18] serial: poll the serial console with G_IO_HUP +Bugzilla: 1452332 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Laurent Vivier +RH-Acked-by: Eduardo Habkost + +From: Roger Pau Monne + +On FreeBSD polling a master pty while the other end is not connected +with G_IO_OUT only results in an endless wait. This is different from +the Linux behaviour, that returns immediately. In order to demonstrate +this, I have the following example code: + +http://xenbits.xen.org/people/royger/test_poll.c + +When executed on Linux: + +$ ./test_poll +In callback + +On FreeBSD instead, the callback never gets called: + +$ ./test_poll + +So, in order to workaround this, poll the source with G_IO_HUP (which +makes the code behave the same way on both Linux and FreeBSD). + +Signed-off-by: Roger Pau Monné +Cc: Peter Crosthwaite +Cc: Michael Tokarev +Cc: "Andreas Färber" +Cc: Paolo Bonzini +Cc: xen-devel@lists.xenproject.org +[Add hw/char/cadence_uart.c too. - Paolo] +Signed-off-by: Paolo Bonzini + +(cherry picked from commit e02bc6de30c44fd668dc0d6e1cd1804f2eed3ed3) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina + +Conflicts: + hw/char/cadence_uart.c + +Downstream doesn't use qemu_chr_fe_add_watch because we don't have +38acd64b1c etc. + + monitor.c + +The changed line is different because we don't have 6cff3e8594 (monitor: +protect outbuf and mux_out with mutex). +--- + hw/char/serial.c | 2 +- + hw/char/virtio-console.c | 3 ++- + hw/usb/redirect.c | 2 +- + monitor.c | 2 +- + 4 files changed, 5 insertions(+), 4 deletions(-) + +diff --git a/hw/char/serial.c b/hw/char/serial.c +index e020b0e..add4738 100644 +--- a/hw/char/serial.c ++++ b/hw/char/serial.c +@@ -246,7 +246,7 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque) + serial_receive1(s, &s->tsr, 1); + } else if (qemu_chr_fe_write(s->chr, &s->tsr, 1) != 1) { + if (s->tsr_retry >= 0 && s->tsr_retry < MAX_XMIT_RETRY && +- qemu_chr_fe_add_watch(s->chr, G_IO_OUT, serial_xmit, s) > 0) { ++ qemu_chr_fe_add_watch(s->chr, G_IO_OUT|G_IO_HUP, serial_xmit, s) > 0) { + s->tsr_retry++; + return FALSE; + } +diff --git a/hw/char/virtio-console.c b/hw/char/virtio-console.c +index 1b01dcd..69dd95a 100644 +--- a/hw/char/virtio-console.c ++++ b/hw/char/virtio-console.c +@@ -66,7 +66,8 @@ static ssize_t flush_buf(VirtIOSerialPort *port, + if (!k->is_console) { + virtio_serial_throttle_port(port, true); + if (!vcon->watch) { +- vcon->watch = qemu_chr_fe_add_watch(vcon->chr, G_IO_OUT, ++ vcon->watch = qemu_chr_fe_add_watch(vcon->chr, ++ G_IO_OUT|G_IO_HUP, + chr_write_unblocked, vcon); + } + } +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index e3b9f32..3fe2106 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -284,7 +284,7 @@ static int usbredir_write(void *priv, uint8_t *data, int count) + r = qemu_chr_fe_write(dev->cs, data, count); + if (r < count) { + if (!dev->watch) { +- dev->watch = qemu_chr_fe_add_watch(dev->cs, G_IO_OUT, ++ dev->watch = qemu_chr_fe_add_watch(dev->cs, G_IO_OUT|G_IO_HUP, + usbredir_write_unblocked, dev); + } + if (r < 0) { +diff --git a/monitor.c b/monitor.c +index 1b28ff3..393a508 100644 +--- a/monitor.c ++++ b/monitor.c +@@ -300,7 +300,7 @@ void monitor_flush(Monitor *mon) + mon->outbuf = tmp; + } + if (mon->watch == 0) { +- mon->watch = qemu_chr_fe_add_watch(mon->chr, G_IO_OUT, ++ mon->watch = qemu_chr_fe_add_watch(mon->chr, G_IO_OUT|G_IO_HUP, + monitor_unblocked, mon); + } + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-serial-remove-watch-on-reset.patch b/SOURCES/kvm-serial-remove-watch-on-reset.patch new file mode 100644 index 0000000..a33f76c --- /dev/null +++ b/SOURCES/kvm-serial-remove-watch-on-reset.patch @@ -0,0 +1,87 @@ +From ac39e63d788b8bcb748f08347312b0fccde7ce0e Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 19 May 2017 00:35:23 +0200 +Subject: [PATCH 18/18] serial: remove watch on reset + +RH-Author: Fam Zheng +Message-id: <20170519003523.21163-19-famz@redhat.com> +Patchwork-id: 75373 +O-Subject: [RHEL-7.3.z qemu-kvm PATCH 18/18] serial: remove watch on reset +Bugzilla: 1452332 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Laurent Vivier +RH-Acked-by: Eduardo Habkost + +From: Paolo Bonzini + +Otherwise, this can cause serial_xmit to be entered with LSR.TEMT=0, +which is invalid and causes an assertion failure. + +Reported-by: Bret Ketchum +Tested-by: Bret Ketchum +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Paolo Bonzini +(cherry picked from commit a1df76da57aa8772a75e7c49f8e3829d07b4c46c) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + hw/char/serial.c | 16 ++++++++++++---- + include/hw/char/serial.h | 1 + + 2 files changed, 13 insertions(+), 4 deletions(-) + +diff --git a/hw/char/serial.c b/hw/char/serial.c +index 69fefb2..39de1ca 100644 +--- a/hw/char/serial.c ++++ b/hw/char/serial.c +@@ -224,6 +224,7 @@ static gboolean serial_watch_cb(GIOChannel *chan, GIOCondition cond, + void *opaque) + { + SerialState *s = opaque; ++ s->watch_tag = 0; + serial_xmit(s); + return FALSE; + } +@@ -254,10 +255,12 @@ static void serial_xmit(SerialState *s) + if (s->mcr & UART_MCR_LOOP) { + /* in loopback mode, say that we just received a char */ + serial_receive1(s, &s->tsr, 1); +- } else if (qemu_chr_fe_write(s->chr, &s->tsr, 1) != 1) { +- if (s->tsr_retry < MAX_XMIT_RETRY && +- qemu_chr_fe_add_watch(s->chr, G_IO_OUT|G_IO_HUP, +- serial_watch_cb, s) > 0) { ++ } else if (qemu_chr_fe_write(s->chr, &s->tsr, 1) != 1 && ++ s->tsr_retry < MAX_XMIT_RETRY) { ++ assert(s->watch_tag == 0); ++ s->watch_tag = qemu_chr_fe_add_watch(s->chr, G_IO_OUT|G_IO_HUP, ++ serial_watch_cb, s); ++ if (s->watch_tag > 0) { + s->tsr_retry++; + return; + } +@@ -656,6 +659,11 @@ static void serial_reset(void *opaque) + { + SerialState *s = opaque; + ++ if (s->watch_tag > 0) { ++ g_source_remove(s->watch_tag); ++ s->watch_tag = 0; ++ } ++ + s->rbr = 0; + s->ier = 0; + s->iir = UART_IIR_NO_INT; +diff --git a/include/hw/char/serial.h b/include/hw/char/serial.h +index 2661f8c..19c7763 100644 +--- a/include/hw/char/serial.h ++++ b/include/hw/char/serial.h +@@ -56,6 +56,7 @@ struct SerialState { + int it_shift; + int baudbase; + uint32_t tsr_retry; ++ guint watch_tag; + uint32_t wakeup; + + /* Time when the last byte was successfully sent out of the tsr */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-serial-reset-thri_pending-on-IER-writes-with-THRI-0.patch b/SOURCES/kvm-serial-reset-thri_pending-on-IER-writes-with-THRI-0.patch new file mode 100644 index 0000000..d7242e3 --- /dev/null +++ b/SOURCES/kvm-serial-reset-thri_pending-on-IER-writes-with-THRI-0.patch @@ -0,0 +1,85 @@ +From 6d2a5ef7994e753197bb9653872601db4e6cff5d Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 19 May 2017 00:35:16 +0200 +Subject: [PATCH 11/18] serial: reset thri_pending on IER writes with THRI=0 + +RH-Author: Fam Zheng +Message-id: <20170519003523.21163-12-famz@redhat.com> +Patchwork-id: 75365 +O-Subject: [RHEL-7.3.z qemu-kvm PATCH 11/18] serial: reset thri_pending on IER writes with THRI=0 +Bugzilla: 1452332 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Laurent Vivier +RH-Acked-by: Eduardo Habkost + +From: Paolo Bonzini + +This is responsible for failure of migration from 2.2 to 2.1, because +thr_ipending is always one in practice. + +serial.c is setting thr_ipending unconditionally. However, thr_ipending +is not used at all if THRI=0, and it will be overwritten again the next +time THRE or THRI changes. For that reason, we can set thr_ipending to +zero every time THRI is reset. + +There is disagreement on whether LSR.THRE should be resampled when IER.THRI +goes from 1 to 1. This patch does not touch the code, leaving that for +QEMU 2.3+. + +This has no semantic change and is enough to fix migration in the common +case where the interrupt is not pending or is reported in IIR. It does not +change the migration format, so 2.2.0 -> 2.1 will remain broken but we +can fix 2.2.1 -> 2.1 without breaking 2.2.1 <-> 2.2.0. + +The case that remains broken (the one in which the subsection is strictly +necessary) is when THRE=1, the THRI interrupt has *not* been acknowledged +yet, and a higher-priority interrupt comes. In this case, you need the +subsection to tell the source that the lower-priority THRI interrupt is +pending. The subsection's breakage of migration, in this case, prevents +continuing the VM on the destination with an invalid state. + +Cc: qemu-stable@nongnu.org +Reported-by: Igor Mammedov +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Paolo Bonzini +(cherry picked from commit 4e02b0fcf5c97579d0d3261c80c65abcf92870fe) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + hw/char/serial.c | 18 ++++++++++++++++-- + 1 file changed, 16 insertions(+), 2 deletions(-) + +diff --git a/hw/char/serial.c b/hw/char/serial.c +index 5ef9b95..15c628f 100644 +--- a/hw/char/serial.c ++++ b/hw/char/serial.c +@@ -320,10 +320,24 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, + s->poll_msl = 0; + } + } +- if (s->lsr & UART_LSR_THRE) { ++ ++ /* Turning on the THRE interrupt on IER can trigger the interrupt ++ * if LSR.THRE=1, even if it had been masked before by reading IIR. ++ * This is not in the datasheet, but Windows relies on it. It is ++ * unclear if THRE has to be resampled every time THRI becomes ++ * 1, or only on the rising edge. Bochs does the latter, and Windows ++ * always toggles IER to all zeroes and back to all ones. But for ++ * now leave it as it has always been in QEMU. ++ * ++ * If IER.THRI is zero, thr_ipending is not used. Set it to zero ++ * so that the thr_ipending subsection is not migrated. ++ */ ++ if ((s->ier & UART_IER_THRI) && (s->lsr & UART_LSR_THRE)) { + s->thr_ipending = 1; +- serial_update_irq(s); ++ } else { ++ s->thr_ipending = 0; + } ++ serial_update_irq(s); + } + break; + case 2: +-- +1.8.3.1 + diff --git a/SOURCES/kvm-serial-separate-serial_xmit-and-serial_watch_cb.patch b/SOURCES/kvm-serial-separate-serial_xmit-and-serial_watch_cb.patch new file mode 100644 index 0000000..698096f --- /dev/null +++ b/SOURCES/kvm-serial-separate-serial_xmit-and-serial_watch_cb.patch @@ -0,0 +1,102 @@ +From 2600e8a94c5434d07e820c7cf5bcd62d69849099 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 19 May 2017 00:35:22 +0200 +Subject: [PATCH 17/18] serial: separate serial_xmit and serial_watch_cb + +RH-Author: Fam Zheng +Message-id: <20170519003523.21163-18-famz@redhat.com> +Patchwork-id: 75368 +O-Subject: [RHEL-7.3.z qemu-kvm PATCH 17/18] serial: separate serial_xmit and serial_watch_cb +Bugzilla: 1452332 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Laurent Vivier +RH-Acked-by: Eduardo Habkost + +From: Paolo Bonzini + +serial_xmit starts transmission of whatever is in the transmitter +register, THR or FIFO; serial_watch_cb is a wrapper around it and is +only used as a qemu_chr_fe_add_watch callback. + +Tested-by: Bret Ketchum +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Paolo Bonzini +(cherry picked from commit b0585e7e07982daa578c3bfef7f6843c89f110a8) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina + +Conflicts: + hw/char/serial.c + +Contextual conflict because the surrounding migration code around the +touched functions is different. +--- + hw/char/serial.c | 18 +++++++++++------- + 1 file changed, 11 insertions(+), 7 deletions(-) + +diff --git a/hw/char/serial.c b/hw/char/serial.c +index fdda802..69fefb2 100644 +--- a/hw/char/serial.c ++++ b/hw/char/serial.c +@@ -104,6 +104,7 @@ do {} while (0) + #endif + + static void serial_receive1(void *opaque, const uint8_t *buf, int size); ++static void serial_xmit(SerialState *s); + + static inline void recv_fifo_put(SerialState *s, uint8_t chr) + { +@@ -219,10 +220,16 @@ static void serial_update_msl(SerialState *s) + qemu_mod_timer(s->modem_status_poll, qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 100); + } + +-static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque) ++static gboolean serial_watch_cb(GIOChannel *chan, GIOCondition cond, ++ void *opaque) + { + SerialState *s = opaque; ++ serial_xmit(s); ++ return FALSE; ++} + ++static void serial_xmit(SerialState *s) ++{ + do { + assert(!(s->lsr & UART_LSR_TEMT)); + if (s->tsr_retry == 0) { +@@ -250,9 +257,9 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque) + } else if (qemu_chr_fe_write(s->chr, &s->tsr, 1) != 1) { + if (s->tsr_retry < MAX_XMIT_RETRY && + qemu_chr_fe_add_watch(s->chr, G_IO_OUT|G_IO_HUP, +- serial_xmit, s) > 0) { ++ serial_watch_cb, s) > 0) { + s->tsr_retry++; +- return FALSE; ++ return; + } + } + s->tsr_retry = 0; +@@ -263,11 +270,8 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque) + + s->last_xmit_ts = qemu_get_clock_ns(vm_clock); + s->lsr |= UART_LSR_TEMT; +- +- return FALSE; + } + +- + static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) + { +@@ -295,7 +299,7 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, + s->lsr &= ~UART_LSR_TEMT; + serial_update_irq(s); + if (s->tsr_retry == 0) { +- serial_xmit(NULL, G_IO_OUT, s); ++ serial_xmit(s); + } + } + break; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-serial-simplify-tsr_retry-reset.patch b/SOURCES/kvm-serial-simplify-tsr_retry-reset.patch new file mode 100644 index 0000000..1325ff3 --- /dev/null +++ b/SOURCES/kvm-serial-simplify-tsr_retry-reset.patch @@ -0,0 +1,49 @@ +From 4a5819d1786be74df4b2393f72d6901e05d0eb4a Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 19 May 2017 00:35:21 +0200 +Subject: [PATCH 16/18] serial: simplify tsr_retry reset + +RH-Author: Fam Zheng +Message-id: <20170519003523.21163-17-famz@redhat.com> +Patchwork-id: 75372 +O-Subject: [RHEL-7.3.z qemu-kvm PATCH 16/18] serial: simplify tsr_retry reset +Bugzilla: 1452332 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Laurent Vivier +RH-Acked-by: Eduardo Habkost + +From: Paolo Bonzini + +Move common code outside the if, and reset tsr_retry even in loopback mode. +Right now it cannot become non-zero, but it will be possible as soon as +we start respecting the baud rate. + +Tested-by: Bret Ketchum +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Paolo Bonzini +(cherry picked from commit bce933b85a34514fe34fa559be1d8ccd1f39f954) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + hw/char/serial.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/hw/char/serial.c b/hw/char/serial.c +index afa1932..fdda802 100644 +--- a/hw/char/serial.c ++++ b/hw/char/serial.c +@@ -254,10 +254,8 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque) + s->tsr_retry++; + return FALSE; + } +- s->tsr_retry = 0; +- } else { +- s->tsr_retry = 0; + } ++ s->tsr_retry = 0; + + /* Transmit another byte if it is already available. It is only + possible when FIFO is enabled and not empty. */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-serial-update-LSR-on-enabling-disabling-FIFOs.patch b/SOURCES/kvm-serial-update-LSR-on-enabling-disabling-FIFOs.patch new file mode 100644 index 0000000..f4b8523 --- /dev/null +++ b/SOURCES/kvm-serial-update-LSR-on-enabling-disabling-FIFOs.patch @@ -0,0 +1,63 @@ +From 727ebf3f24a6f519aab1306bad6e63014c76aec5 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 19 May 2017 00:35:18 +0200 +Subject: [PATCH 13/18] serial: update LSR on enabling/disabling FIFOs + +RH-Author: Fam Zheng +Message-id: <20170519003523.21163-14-famz@redhat.com> +Patchwork-id: 75369 +O-Subject: [RHEL-7.3.z qemu-kvm PATCH 13/18] serial: update LSR on enabling/disabling FIFOs +Bugzilla: 1452332 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Laurent Vivier +RH-Acked-by: Eduardo Habkost + +From: Paolo Bonzini + +When the transmit FIFO is emptied or enabled, the transmitter +hold register is empty. When it is disabled, it is also emptied and +in addition the previous contents of the transmitter hold register +are discarded. In either case, the THRE bit in LSR must be set and +THRI raised. + +When the receive FIFO is emptied or enabled, the data ready and break +bits must be cleared in LSR. Likewise when the receive FIFO is disabled. + +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Paolo Bonzini +(cherry picked from commit 023c3a9707d0d9259a1e858cdf7804dd10973fca) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina + +Conflicts: + hw/char/serial.c + +Contextual conflict because upstream uses new timer API timer_del while +downstream still uses qemu_del_timer. +--- + hw/char/serial.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/hw/char/serial.c b/hw/char/serial.c +index c2be4bd..e0d29a8 100644 +--- a/hw/char/serial.c ++++ b/hw/char/serial.c +@@ -351,12 +351,15 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, + /* FIFO clear */ + + if (val & UART_FCR_RFR) { ++ s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); + qemu_del_timer(s->fifo_timeout_timer); + s->timeout_ipending=0; + fifo8_reset(&s->recv_fifo); + } + + if (val & UART_FCR_XFR) { ++ s->lsr |= UART_LSR_THRE; ++ s->thr_ipending = 1; + fifo8_reset(&s->xmit_fifo); + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-spice-fix-spice_chr_add_watch-pre-condition.patch b/SOURCES/kvm-spice-fix-spice_chr_add_watch-pre-condition.patch new file mode 100644 index 0000000..35d702b --- /dev/null +++ b/SOURCES/kvm-spice-fix-spice_chr_add_watch-pre-condition.patch @@ -0,0 +1,49 @@ +From 9b379db2f11257f5ef88979fdf9660eaa0ad6b4b Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Tue, 6 Jun 2017 06:16:56 +0200 +Subject: [PATCH] spice: fix spice_chr_add_watch() pre-condition +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Fam Zheng +Message-id: <20170606061656.29212-2-famz@redhat.com> +Patchwork-id: 75488 +O-Subject: [RHEL-7.3.z qemu-kvm PATCH 1/1] spice: fix spice_chr_add_watch() pre-condition +Bugzilla: 1452332 +RH-Acked-by: John Snow +RH-Acked-by: Eduardo Habkost +RH-Acked-by: Miroslav Rezanina + +From: Marc-André Lureau + +Since e02bc6de30c44fd668dc0d6e1cd1804f2eed3ed3, add_watch() is called +with G_IO_HUP. Even if spice-qemu-char ignores this flag, the +precondition must be changed. + +https://bugzilla.redhat.com/show_bug.cgi?id=1128992 + +Signed-off-by: Gerd Hoffmann +(cherry picked from commit f7a8beb5e6a13dc924895244777d9ef08b23b367) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + spice-qemu-char.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/spice-qemu-char.c b/spice-qemu-char.c +index 6d147a7..079c214 100644 +--- a/spice-qemu-char.c ++++ b/spice-qemu-char.c +@@ -171,7 +171,7 @@ static GSource *spice_chr_add_watch(CharDriverState *chr, GIOCondition cond) + SpiceCharDriver *scd = chr->opaque; + SpiceCharSource *src; + +- assert(cond == G_IO_OUT); ++ assert(cond & G_IO_OUT); + + src = (SpiceCharSource *)g_source_new(&SpiceCharSourceFuncs, + sizeof(SpiceCharSource)); +-- +1.8.3.1 + diff --git a/SPECS/qemu-kvm.spec b/SPECS/qemu-kvm.spec index 2f9a30f..e9786e4 100644 --- a/SPECS/qemu-kvm.spec +++ b/SPECS/qemu-kvm.spec @@ -76,7 +76,7 @@ Obsoletes: %1 < %{obsoletes_version} \ Summary: QEMU is a FAST! processor emulator Name: %{pkgname}%{?pkgsuffix} Version: 1.5.3 -Release: 126%{?dist}.6 +Release: 126%{?dist}.9 # Epoch because we pushed a qemu-1.0 package. AIUI this can't ever be dropped Epoch: 10 License: GPLv2+ and LGPLv2+ and BSD @@ -3446,6 +3446,46 @@ Patch1693: kvm-cirrus-stop-passing-around-dst-pointers-in-the-blitt.patch Patch1694: kvm-cirrus-stop-passing-around-src-pointers-in-the-blitt.patch # For bz#1430059 - CVE-2016-9603 qemu-kvm: Qemu: cirrus: heap buffer overflow via vnc connection [rhel-7.3.z] Patch1695: kvm-cirrus-fix-off-by-one-in-cirrus_bitblt_rop_bkwd_tran.patch +# For bz#1452332 - RHEL 7.2 based VM (Virtual Machine) hung for several hours apparently waiting for lock held by main_loop +Patch1696: kvm-char-serial-cosmetic-fixes.patch +# For bz#1452332 - RHEL 7.2 based VM (Virtual Machine) hung for several hours apparently waiting for lock held by main_loop +Patch1697: kvm-char-serial-Use-generic-Fifo8.patch +# For bz#1452332 - RHEL 7.2 based VM (Virtual Machine) hung for several hours apparently waiting for lock held by main_loop +Patch1698: kvm-char-serial-serial_ioport_write-Factor-out-common-co.patch +# For bz#1452332 - RHEL 7.2 based VM (Virtual Machine) hung for several hours apparently waiting for lock held by main_loop +Patch1699: kvm-char-serial-fix-copy-paste-error-fifo8_is_full-vs-em.patch +# For bz#1452332 - RHEL 7.2 based VM (Virtual Machine) hung for several hours apparently waiting for lock held by main_loop +Patch1700: kvm-char-serial-Fix-emptyness-check.patch +# For bz#1452332 - RHEL 7.2 based VM (Virtual Machine) hung for several hours apparently waiting for lock held by main_loop +Patch1701: kvm-char-serial-Fix-emptyness-handling.patch +# For bz#1452332 - RHEL 7.2 based VM (Virtual Machine) hung for several hours apparently waiting for lock held by main_loop +Patch1702: kvm-serial-poll-the-serial-console-with-G_IO_HUP.patch +# For bz#1452332 - RHEL 7.2 based VM (Virtual Machine) hung for several hours apparently waiting for lock held by main_loop +Patch1703: kvm-serial-change-retry-logic-to-avoid-concurrency.patch +# For bz#1452332 - RHEL 7.2 based VM (Virtual Machine) hung for several hours apparently waiting for lock held by main_loop +Patch1704: kvm-qemu-char-ignore-flow-control-if-a-PTY-s-slave-is-no.patch +# For bz#1452332 - RHEL 7.2 based VM (Virtual Machine) hung for several hours apparently waiting for lock held by main_loop +Patch1705: kvm-serial-check-if-backed-by-a-physical-serial-port-at-.patch +# For bz#1452332 - RHEL 7.2 based VM (Virtual Machine) hung for several hours apparently waiting for lock held by main_loop +Patch1706: kvm-serial-reset-thri_pending-on-IER-writes-with-THRI-0.patch +# For bz#1452332 - RHEL 7.2 based VM (Virtual Machine) hung for several hours apparently waiting for lock held by main_loop +Patch1707: kvm-serial-clean-up-THRE-TEMT-handling.patch +# For bz#1452332 - RHEL 7.2 based VM (Virtual Machine) hung for several hours apparently waiting for lock held by main_loop +Patch1708: kvm-serial-update-LSR-on-enabling-disabling-FIFOs.patch +# For bz#1452332 - RHEL 7.2 based VM (Virtual Machine) hung for several hours apparently waiting for lock held by main_loop +Patch1709: kvm-serial-only-resample-THR-interrupt-on-rising-edge-of.patch +# For bz#1452332 - RHEL 7.2 based VM (Virtual Machine) hung for several hours apparently waiting for lock held by main_loop +Patch1710: kvm-serial-make-tsr_retry-unsigned.patch +# For bz#1452332 - RHEL 7.2 based VM (Virtual Machine) hung for several hours apparently waiting for lock held by main_loop +Patch1711: kvm-serial-simplify-tsr_retry-reset.patch +# For bz#1452332 - RHEL 7.2 based VM (Virtual Machine) hung for several hours apparently waiting for lock held by main_loop +Patch1712: kvm-serial-separate-serial_xmit-and-serial_watch_cb.patch +# For bz#1452332 - RHEL 7.2 based VM (Virtual Machine) hung for several hours apparently waiting for lock held by main_loop +Patch1713: kvm-serial-remove-watch-on-reset.patch +# For bz#1452332 - RHEL 7.2 based VM (Virtual Machine) hung for several hours apparently waiting for lock held by main_loop +Patch1714: kvm-char-change-qemu_chr_fe_add_watch-to-return-unsigned.patch +# For bz#1452332 - RHEL 7.2 based VM (Virtual Machine) hung for several hours apparently waiting for lock held by main_loop +Patch1715: kvm-spice-fix-spice_chr_add_watch-pre-condition.patch BuildRequires: zlib-devel @@ -5321,6 +5361,26 @@ cp %{SOURCE18} pc-bios # keep "make check" happy %patch1693 -p1 %patch1694 -p1 %patch1695 -p1 +%patch1696 -p1 +%patch1697 -p1 +%patch1698 -p1 +%patch1699 -p1 +%patch1700 -p1 +%patch1701 -p1 +%patch1702 -p1 +%patch1703 -p1 +%patch1704 -p1 +%patch1705 -p1 +%patch1706 -p1 +%patch1707 -p1 +%patch1708 -p1 +%patch1709 -p1 +%patch1710 -p1 +%patch1711 -p1 +%patch1712 -p1 +%patch1713 -p1 +%patch1714 -p1 +%patch1715 -p1 %build buildarch="%{kvm_target}-softmmu" @@ -5766,6 +5826,38 @@ sh %{_sysconfdir}/sysconfig/modules/kvm.modules &> /dev/null || : %{_mandir}/man8/qemu-nbd.8* %changelog +* Tue Jun 06 2017 Miroslav Rezanina - 1.5.3-126.el7_3.9 +- kvm-spice-fix-spice_chr_add_watch-pre-condition.patch [bz#1452332] +- Resolves: bz#1452332 + (RHEL 7.2 based VM (Virtual Machine) hung for several hours apparently waiting for lock held by main_loop) + +* Wed May 24 2017 Miroslav Rezanina - 1.5.3-126.el7_3.8 +- kvm-char-change-qemu_chr_fe_add_watch-to-return-unsigned.patch [bz#1452332] +- Resolves: bz#1452332 + (RHEL 7.2 based VM (Virtual Machine) hung for several hours apparently waiting for lock held by main_loop) + +* Mon May 22 2017 Miroslav Rezanina - 1.5.3-126.el7_3.7 +- kvm-char-serial-cosmetic-fixes.patch [bz#1452332] +- kvm-char-serial-Use-generic-Fifo8.patch [bz#1452332] +- kvm-char-serial-serial_ioport_write-Factor-out-common-co.patch [bz#1452332] +- kvm-char-serial-fix-copy-paste-error-fifo8_is_full-vs-em.patch [bz#1452332] +- kvm-char-serial-Fix-emptyness-check.patch [bz#1452332] +- kvm-char-serial-Fix-emptyness-handling.patch [bz#1452332] +- kvm-serial-poll-the-serial-console-with-G_IO_HUP.patch [bz#1452332] +- kvm-serial-change-retry-logic-to-avoid-concurrency.patch [bz#1452332] +- kvm-qemu-char-ignore-flow-control-if-a-PTY-s-slave-is-no.patch [bz#1452332] +- kvm-serial-check-if-backed-by-a-physical-serial-port-at-.patch [bz#1452332] +- kvm-serial-reset-thri_pending-on-IER-writes-with-THRI-0.patch [bz#1452332] +- kvm-serial-clean-up-THRE-TEMT-handling.patch [bz#1452332] +- kvm-serial-update-LSR-on-enabling-disabling-FIFOs.patch [bz#1452332] +- kvm-serial-only-resample-THR-interrupt-on-rising-edge-of.patch [bz#1452332] +- kvm-serial-make-tsr_retry-unsigned.patch [bz#1452332] +- kvm-serial-simplify-tsr_retry-reset.patch [bz#1452332] +- kvm-serial-separate-serial_xmit-and-serial_watch_cb.patch [bz#1452332] +- kvm-serial-remove-watch-on-reset.patch [bz#1452332] +- Resolves: bz#1452332 + (RHEL 7.2 based VM (Virtual Machine) hung for several hours apparently waiting for lock held by main_loop) + * Fri Mar 24 2017 Miroslav Rezanina - 1.5.3-126.el7_3.6 - kvm-fix-cirrus_vga-fix-OOB-read-case-qemu-Segmentation-f.patch [bz#1430059] - kvm-cirrus-vnc-zap-bitblit-support-from-console-code.patch [bz#1430059]