Browse Source

mos6522: update counters when timer interrupts are off

Even if the interrupts are off, counters must be updated because
they are running anyway and kernel can try to read them
(it's the case with g3beige kernel).

Reported-by: Andrew Randrianasulu <randrianasulu@gmail.com>
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
Message-Id: <20191125141414.5015-1-laurent@vivier.eu>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Laurent Vivier 5 năm trước cách đây
mục cha
commit
6cf80f90c4
1 tập tin đã thay đổi với 6 bổ sung2 xóa
  1. 6 2
      hw/misc/mos6522.c

+ 6 - 2
hw/misc/mos6522.c

@@ -113,6 +113,10 @@ static int64_t get_next_irq_time(MOS6522State *s, MOS6522Timer *ti,
     int64_t d, next_time;
     int64_t d, next_time;
     unsigned int counter;
     unsigned int counter;
 
 
+    if (ti->frequency == 0) {
+        return INT64_MAX;
+    }
+
     /* current counter value */
     /* current counter value */
     d = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - ti->load_time,
     d = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - ti->load_time,
                  ti->frequency, NANOSECONDS_PER_SECOND);
                  ti->frequency, NANOSECONDS_PER_SECOND);
@@ -149,10 +153,10 @@ static void mos6522_timer1_update(MOS6522State *s, MOS6522Timer *ti,
     if (!ti->timer) {
     if (!ti->timer) {
         return;
         return;
     }
     }
+    ti->next_irq_time = get_next_irq_time(s, ti, current_time);
     if ((s->ier & T1_INT) == 0 || (s->acr & T1MODE) != T1MODE_CONT) {
     if ((s->ier & T1_INT) == 0 || (s->acr & T1MODE) != T1MODE_CONT) {
         timer_del(ti->timer);
         timer_del(ti->timer);
     } else {
     } else {
-        ti->next_irq_time = get_next_irq_time(s, ti, current_time);
         timer_mod(ti->timer, ti->next_irq_time);
         timer_mod(ti->timer, ti->next_irq_time);
     }
     }
 }
 }
@@ -163,10 +167,10 @@ static void mos6522_timer2_update(MOS6522State *s, MOS6522Timer *ti,
     if (!ti->timer) {
     if (!ti->timer) {
         return;
         return;
     }
     }
+    ti->next_irq_time = get_next_irq_time(s, ti, current_time);
     if ((s->ier & T2_INT) == 0) {
     if ((s->ier & T2_INT) == 0) {
         timer_del(ti->timer);
         timer_del(ti->timer);
     } else {
     } else {
-        ti->next_irq_time = get_next_irq_time(s, ti, current_time);
         timer_mod(ti->timer, ti->next_irq_time);
         timer_mod(ti->timer, ti->next_irq_time);
     }
     }
 }
 }