>On 24/07/2017 20:35, Peng Hao wrote:
>> When a windows vm starts, periodic timer of rtc will stop several times. >> windows kernel will check whether REG_A_UIP is changed. REG_C's interrupt >> flags will not be cleared when periodic timer stops and the update timer >> will switch to alarm timer. So the expiration time of alarm timer is very >> long and REG_A_UIP will not vary.At last windows kernel will repeat to >> check REG_A_UIP all the time. >This should not happen. REG_A_UIP is set and cleared in register A >every second, like this: > case RTC_REG_A: > 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 = s->cmos_data[s->cmos_index] > break when periodic timer stop, update timer is set to a long expire time (as alarm timer). So update_in_progress always return 1 and REG_A_UIP is never cleared. >where update_in_progress does: > guest_nsec = get_guest_rtc_ns(s) > /* UIP bit will be set at last 244us of every second. */ > if ((guest_nsec % NANOSECONDS_PER_SECOND) >= > (NANOSECONDS_PER_SECOND - UIP_HOLD_LENGTH)) { > return 1 > } > return 0 >This is done even if the timer is not pending. >How can the bug be reproduced? many windows VMs reboot at the same time.some VM's vcpu thread go to a infinite loop at the starting stage. >Paolo > Signed-off-by: Peng Hao <peng.h...@zte.com.cn> > Signed-off-by: Liu Yi <liu.y...@zte.com.cn> > --- > hw/timer/mc146818rtc.c | 4 +++- > 1 file changed, 3 insertions(+), 1 deletion(-) > > diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c > index 1b8d3d7..aa55fae 100644 > --- a/hw/timer/mc146818rtc.c > +++ b/hw/timer/mc146818rtc.c > @@ -457,6 +457,8 @@ static void rtc_update_timer(void *opaque) > if ((new_irqs & s->cmos_data[RTC_REG_B]) != 0) { > s->cmos_data[RTC_REG_C] |= REG_C_IRQF > qemu_irq_raise(s->irq) > + } else if ((s->cmos_data[RTC_REG_B] & REG_B_UIE) == 0) { > + s->cmos_data[RTC_REG_C] &= ~REG_C_UF > } > check_update_timer(s) > } > @@ -559,7 +561,7 @@ static void cmos_ioport_write(void *opaque, hwaddr addr, > s->cmos_data[RTC_REG_C] |= REG_C_IRQF > qemu_irq_raise(s->irq) > } else { > - s->cmos_data[RTC_REG_C] &= ~REG_C_IRQF > + s->cmos_data[RTC_REG_C] &= ~(REG_C_UF | REG_C_IRQF) > qemu_irq_lower(s->irq) > } > s->cmos_data[RTC_REG_B] = data >