[PATCH] Fix negative lost clock causing VM crash

shenjiatong posted 1 patch 1 week ago
hw/rtc/mc146818rtc.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
[PATCH] Fix negative lost clock causing VM crash
Posted by shenjiatong 1 week ago
Under situation where virtual machine is running in a deployment where
the system time is unstable, there is a chance that legacy OpenStack
Windows machines without stimer enabled will crash if system time moves
backwards and diftfix=slew is enabled. This primarily caused by the fact
the system time moves faster than NTP server and after synchronization,
system time flows backwards.

Signed-off-by: shenjiatong <yshxxsjt715@163.com>
---
 hw/rtc/mc146818rtc.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c
index 8ccee9a385..fa5d7915b1 100644
--- a/hw/rtc/mc146818rtc.c
+++ b/hw/rtc/mc146818rtc.c
@@ -180,7 +180,6 @@ static void periodic_timer_update(MC146818RtcState *s, int64_t current_time,
                                 RTC_CLOCK_RATE, NANOSECONDS_PER_SECOND);
         last_periodic_clock = next_periodic_clock - old_period;
         lost_clock = cur_clock - last_periodic_clock;
-        assert(lost_clock >= 0);
     }
 
     /*
@@ -199,10 +198,15 @@ static void periodic_timer_update(MC146818RtcState *s, int64_t current_time,
      */
     if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) {
         uint32_t old_irq_coalesced = s->irq_coalesced;
+        if (lost_clock >= 0) {
+            lost_clock += old_irq_coalesced * old_period;
+            s->irq_coalesced = lost_clock / s->period;
+            lost_clock %= s->period;
+        } else {
+            s->irq_coalesced = 0;
+            lost_clock = 0;
+        }
 
-        lost_clock += old_irq_coalesced * old_period;
-        s->irq_coalesced = lost_clock / s->period;
-        lost_clock %= s->period;
         if (old_irq_coalesced != s->irq_coalesced ||
             old_period != s->period) {
             DPRINTF_C("cmos: coalesced irqs scaled from %d to %d, "
@@ -215,6 +219,7 @@ static void periodic_timer_update(MC146818RtcState *s, int64_t current_time,
          * no way to compensate the interrupt if LOST_TICK_POLICY_SLEW
          * is not used, we should make the time progress anyway.
          */
+        lost_clock = MAX(0, lost_clock);
         lost_clock = MIN(lost_clock, period);
     }
 
-- 
2.43.0