static void rtc_update_irq(RTCState *s) { ASSERT(spin_is_locked(&s->lock)); if ( rtc_mode_is(s, strict) && (s->hw.cmos_data[RTC_REG_C] & RTC_IRQF) ) return; /* IRQ is raised if any source is both raised & enabled */ if ( !(s->hw.cmos_data[RTC_REG_B] & s->hw.cmos_data[RTC_REG_C] & (RTC_PF | RTC_AF | RTC_UF)) ) return; s->hw.cmos_data[RTC_REG_C] |= RTC_IRQF; if ( rtc_mode_is(s, no_ack) ) hvm_isa_irq_deassert(vrtc_domain(s), RTC_IRQ); hvm_isa_irq_assert(vrtc_domain(s), RTC_IRQ); }
static uint32_t rtc_ioport_read(RTCState *s, uint32_t addr) { int ret; struct domain *d = vrtc_domain(s); if ( (addr & 1) == 0 ) return 0xff; spin_lock(&s->lock); switch ( s->hw.cmos_index ) { case RTC_SECONDS: case RTC_MINUTES: case RTC_HOURS: case RTC_DAY_OF_WEEK: case RTC_DAY_OF_MONTH: case RTC_MONTH: case RTC_YEAR: /* if not in set mode, adjust cmos before reading*/ if (!(s->hw.cmos_data[RTC_REG_B] & RTC_SET)) { s->current_tm = gmtime(get_localtime(d)); rtc_copy_date(s); } ret = s->hw.cmos_data[s->hw.cmos_index]; break; case RTC_REG_A: ret = s->hw.cmos_data[s->hw.cmos_index]; if ((s->use_timer == 0) && update_in_progress(s)) ret |= RTC_UIP; break; case RTC_REG_C: ret = s->hw.cmos_data[s->hw.cmos_index]; s->hw.cmos_data[RTC_REG_C] = 0x00; if ( (ret & RTC_IRQF) && !rtc_mode_is(s, no_ack) ) hvm_isa_irq_deassert(d, RTC_IRQ); rtc_update_irq(s); check_update_timer(s); alarm_timer_update(s); rtc_timer_update(s); break; default: ret = s->hw.cmos_data[s->hw.cmos_index]; break; } spin_unlock(&s->lock); return ret; }
bool_t rtc_periodic_interrupt(void *opaque) { RTCState *s = opaque; bool_t ret; spin_lock(&s->lock); ret = rtc_mode_is(s, no_ack) || !(s->hw.cmos_data[RTC_REG_C] & RTC_IRQF); if ( rtc_mode_is(s, no_ack) || !(s->hw.cmos_data[RTC_REG_C] & RTC_PF) ) { s->hw.cmos_data[RTC_REG_C] |= RTC_PF; rtc_update_irq(s); } else if ( ++(s->pt_dead_ticks) >= 10 ) { /* VM is ignoring its RTC; no point in running the timer */ destroy_periodic_time(&s->pt); s->pt_code = 0; } if ( !(s->hw.cmos_data[RTC_REG_C] & RTC_IRQF) ) ret = 0; spin_unlock(&s->lock); return ret; }
/* Called by the VPT code after it's injected a PF interrupt for us. * Fix up the register state to reflect what happened. */ static void rtc_pf_callback(struct vcpu *v, void *opaque) { RTCState *s = opaque; spin_lock(&s->lock); if ( !rtc_mode_is(s, no_ack) && (s->hw.cmos_data[RTC_REG_C] & RTC_IRQF) && ++(s->pt_dead_ticks) >= 10 ) { /* VM is ignoring its RTC; no point in running the timer */ TRACE_0D(TRC_HVM_EMUL_RTC_STOP_TIMER); destroy_periodic_time(&s->pt); s->period = 0; } s->hw.cmos_data[RTC_REG_C] |= RTC_PF|RTC_IRQF; spin_unlock(&s->lock); }