diff options
Diffstat (limited to 'hw/timer/mc146818rtc.c')
-rw-r--r-- | hw/timer/mc146818rtc.c | 15 |
1 files changed, 9 insertions, 6 deletions
diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c index ffb2c6a33e..82843ed03f 100644 --- a/hw/timer/mc146818rtc.c +++ b/hw/timer/mc146818rtc.c @@ -294,6 +294,7 @@ static void check_update_timer(RTCState *s) * them to occur. */ if ((s->cmos_data[RTC_REG_A] & 0x60) == 0x60) { + assert((s->cmos_data[RTC_REG_A] & REG_A_UIP) == 0); timer_del(s->update_timer); return; } @@ -309,8 +310,12 @@ static void check_update_timer(RTCState *s) s->next_alarm_time = next_update_time + (next_alarm_sec - 1) * NANOSECONDS_PER_SECOND; - /* If UF is already set, we might be able to optimize. */ - if (s->cmos_data[RTC_REG_C] & REG_C_UF) { + /* If update_in_progress latched the UIP bit, we must keep the timer + * programmed to the next second, so that UIP is cleared. Otherwise, + * if UF is already set, we might be able to optimize. + */ + if (!(s->cmos_data[RTC_REG_A] & REG_A_UIP) && + (s->cmos_data[RTC_REG_C] & REG_C_UF)) { /* If AF cannot change (i.e. either it is set already, or * SET=1 and then the time is not updated), nothing to do. */ @@ -725,12 +730,10 @@ static uint64_t cmos_ioport_read(void *opaque, hwaddr addr, ret = s->cmos_data[s->cmos_index]; break; case RTC_REG_A: + ret = s->cmos_data[s->cmos_index]; if (update_in_progress(s)) { - s->cmos_data[s->cmos_index] |= REG_A_UIP; - } else { - s->cmos_data[s->cmos_index] &= ~REG_A_UIP; + ret |= REG_A_UIP; } - ret = s->cmos_data[s->cmos_index]; break; case RTC_REG_C: ret = s->cmos_data[s->cmos_index]; |