cryptospore / rpms / qemu-kvm

Forked from rpms/qemu-kvm 2 years ago
Clone
9ae3a8
From 09ff2706109ce647d1fe59e99f44f96810d80b7c Mon Sep 17 00:00:00 2001
9ae3a8
From: Fam Zheng <famz@redhat.com>
9ae3a8
Date: Thu, 18 May 2017 09:21:24 +0200
9ae3a8
Subject: [PATCH 11/18] serial: reset thri_pending on IER writes with THRI=0
9ae3a8
9ae3a8
RH-Author: Fam Zheng <famz@redhat.com>
9ae3a8
Message-id: <20170518092131.16571-12-famz@redhat.com>
9ae3a8
Patchwork-id: 75302
9ae3a8
O-Subject: [RHEL-7.4 qemu-kvm PATCH v3 11/18] serial: reset thri_pending on IER writes with THRI=0
9ae3a8
Bugzilla: 1451470
9ae3a8
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
9ae3a8
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
9ae3a8
RH-Acked-by: Eduardo Habkost <ehabkost@redhat.com>
9ae3a8
9ae3a8
From: Paolo Bonzini <pbonzini@redhat.com>
9ae3a8
9ae3a8
This is responsible for failure of migration from 2.2 to 2.1, because
9ae3a8
thr_ipending is always one in practice.
9ae3a8
9ae3a8
serial.c is setting thr_ipending unconditionally.  However, thr_ipending
9ae3a8
is not used at all if THRI=0, and it will be overwritten again the next
9ae3a8
time THRE or THRI changes.  For that reason, we can set thr_ipending to
9ae3a8
zero every time THRI is reset.
9ae3a8
9ae3a8
There is disagreement on whether LSR.THRE should be resampled when IER.THRI
9ae3a8
goes from 1 to 1.  This patch does not touch the code, leaving that for
9ae3a8
QEMU 2.3+.
9ae3a8
9ae3a8
This has no semantic change and is enough to fix migration in the common
9ae3a8
case where the interrupt is not pending or is reported in IIR.  It does not
9ae3a8
change the migration format, so 2.2.0 -> 2.1 will remain broken but we
9ae3a8
can fix 2.2.1 -> 2.1 without breaking 2.2.1 <-> 2.2.0.
9ae3a8
9ae3a8
The case that remains broken (the one in which the subsection is strictly
9ae3a8
necessary) is when THRE=1, the THRI interrupt has *not* been acknowledged
9ae3a8
yet, and a higher-priority interrupt comes.  In this case, you need the
9ae3a8
subsection to tell the source that the lower-priority THRI interrupt is
9ae3a8
pending.  The subsection's breakage of migration, in this case, prevents
9ae3a8
continuing the VM on the destination with an invalid state.
9ae3a8
9ae3a8
Cc: qemu-stable@nongnu.org
9ae3a8
Reported-by: Igor Mammedov <imammedo@redhat.com>
9ae3a8
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
9ae3a8
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
9ae3a8
(cherry picked from commit 4e02b0fcf5c97579d0d3261c80c65abcf92870fe)
9ae3a8
Signed-off-by: Fam Zheng <famz@redhat.com>
9ae3a8
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
---
9ae3a8
 hw/char/serial.c | 18 ++++++++++++++++--
9ae3a8
 1 file changed, 16 insertions(+), 2 deletions(-)
9ae3a8
9ae3a8
diff --git a/hw/char/serial.c b/hw/char/serial.c
9ae3a8
index 5ef9b95..15c628f 100644
9ae3a8
--- a/hw/char/serial.c
9ae3a8
+++ b/hw/char/serial.c
9ae3a8
@@ -320,10 +320,24 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
9ae3a8
                      s->poll_msl = 0;
9ae3a8
                 }
9ae3a8
             }
9ae3a8
-            if (s->lsr & UART_LSR_THRE) {
9ae3a8
+
9ae3a8
+            /* Turning on the THRE interrupt on IER can trigger the interrupt
9ae3a8
+             * if LSR.THRE=1, even if it had been masked before by reading IIR.
9ae3a8
+             * This is not in the datasheet, but Windows relies on it.  It is
9ae3a8
+             * unclear if THRE has to be resampled every time THRI becomes
9ae3a8
+             * 1, or only on the rising edge.  Bochs does the latter, and Windows
9ae3a8
+             * always toggles IER to all zeroes and back to all ones.  But for
9ae3a8
+             * now leave it as it has always been in QEMU.
9ae3a8
+             *
9ae3a8
+             * If IER.THRI is zero, thr_ipending is not used.  Set it to zero
9ae3a8
+             * so that the thr_ipending subsection is not migrated.
9ae3a8
+             */
9ae3a8
+            if ((s->ier & UART_IER_THRI) && (s->lsr & UART_LSR_THRE)) {
9ae3a8
                 s->thr_ipending = 1;
9ae3a8
-                serial_update_irq(s);
9ae3a8
+            } else {
9ae3a8
+                s->thr_ipending = 0;
9ae3a8
             }
9ae3a8
+            serial_update_irq(s);
9ae3a8
         }
9ae3a8
         break;
9ae3a8
     case 2:
9ae3a8
-- 
9ae3a8
1.8.3.1
9ae3a8