static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) { RTCState *s = opaque; if ((addr & 1) == 0) { s->cmos_index = data & 0x7f; } else { CMOS_DPRINTF("cmos: write index=0x%02x val=0x%02x\n", s->cmos_index, data); switch(s->cmos_index) { case RTC_SECONDS_ALARM: case RTC_MINUTES_ALARM: case RTC_HOURS_ALARM: /* XXX: not supported */ s->cmos_data[s->cmos_index] = data; break; 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: s->cmos_data[s->cmos_index] = data; /* if in set mode, do not update the time */ if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { rtc_set_time(s); } break; case RTC_REG_A: /* UIP bit is read only */ s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) | (s->cmos_data[RTC_REG_A] & REG_A_UIP); rtc_timer_update(s, qemu_get_clock(rtc_clock)); break; case RTC_REG_B: if (data & REG_B_SET) { /* set mode: reset UIP mode */ s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; data &= ~REG_B_UIE; } else { /* if disabling set mode, update the time */ if (s->cmos_data[RTC_REG_B] & REG_B_SET) { rtc_set_time(s); } } s->cmos_data[RTC_REG_B] = data; rtc_timer_update(s, qemu_get_clock(rtc_clock)); break; case RTC_REG_C: case RTC_REG_D: /* cannot write to them */ break; default: s->cmos_data[s->cmos_index] = data; break; } } }
/* Reload the hardware state from a saved domain */ static int rtc_load(struct domain *d, hvm_domain_context_t *h) { RTCState *s = domain_vrtc(d); if ( !has_vrtc(d) ) return -ENODEV; spin_lock(&s->lock); /* Restore the registers */ if ( hvm_load_entry(RTC, h, &s->hw) != 0 ) { spin_unlock(&s->lock); return -EINVAL; } /* Reset the wall-clock time. In normal running, this runs with host * time, so let's keep doing that. */ s->current_tm = gmtime(get_localtime(d)); rtc_copy_date(s); /* Reset the periodic interrupt timer based on the registers */ rtc_timer_update(s); check_update_timer(s); alarm_timer_update(s); spin_unlock(&s->lock); return 0; }
static void rtc_periodic_timer(void *opaque) { RTCState *s = opaque; rtc_timer_update(s, s->next_periodic_time); if (s->cmos_data[RTC_REG_B] & REG_B_PIE) { s->cmos_data[RTC_REG_C] |= 0xc0; #ifdef TARGET_I386 if(rtc_td_hack) { if (s->irq_reinject_on_ack_count >= RTC_REINJECT_ON_ACK_COUNT) s->irq_reinject_on_ack_count = 0; apic_reset_irq_delivered(); qemu_irq_raise(s->irq); if (!apic_get_irq_delivered()) { s->irq_coalesced++; rtc_coalesced_timer_update(s); DPRINTF_C("cmos: coalesced irqs increased to %d\n", s->irq_coalesced); } } else #endif qemu_irq_raise(s->irq); } if (s->cmos_data[RTC_REG_B] & REG_B_SQWE) { /* Not square wave at all but we don't want 2048Hz interrupts! Must be seen as a pulse. */ qemu_irq_raise(s->sqw_irq); } }
static void rtc_periodic_timer(void *opaque) { RTCState *s = opaque; rtc_timer_update(s, s->next_periodic_time); if (s->cmos_data[RTC_REG_B] & REG_B_PIE) { s->cmos_data[RTC_REG_C] |= 0xc0; #ifdef TARGET_I386 if(rtc_td_hack) { apic_reset_irq_delivered(); rtc_irq_raise(s->irq); if (!apic_get_irq_delivered()) { s->irq_coalesced++; rtc_coalesced_timer_update(s); } } else #endif rtc_irq_raise(s->irq); } if (s->cmos_data[RTC_REG_B] & REG_B_SQWE) { /* Not square wave at all but we don't want 2048Hz interrupts! Must be seen as a pulse. */ qemu_irq_raise(s->sqw_irq); } }
void rtc_callback(void *arg){ rtc_timer_update(true); if(soft_watchdog > 0){ soft_watchdog--; if(soft_watchdog == 0) system_restart(); } }
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; }
static void rtc_timer_update(RTCState *s, int64_t current_time) { int period_code, period; int64_t cur_clock, next_irq_clock; period_code = s->cmos_data[RTC_REG_A] & 0x0f; #if defined TARGET_I386 || defined TARGET_X86_64 /* disable periodic timer if hpet is in legacy mode, since interrupts are * disabled anyway. */ if (period_code != 0 && (s->cmos_data[RTC_REG_B] & REG_B_PIE) && !hpet_in_legacy_mode()) { #else if (period_code != 0 && (s->cmos_data[RTC_REG_B] & REG_B_PIE)) { #endif if (period_code <= 2) period_code += 7; /* period in 32 Khz cycles */ period = 1 << (period_code - 1); #ifdef TARGET_I386 if(period != s->period) s->irq_coalesced = (s->irq_coalesced * s->period) / period; s->period = period; #endif /* compute 32 khz clock */ cur_clock = muldiv64(current_time, 32768, ticks_per_sec); next_irq_clock = (cur_clock & ~(period - 1)) + period; s->next_periodic_time = muldiv64(next_irq_clock, ticks_per_sec, 32768) + 1; qemu_mod_timer(s->periodic_timer, s->next_periodic_time); } else { #ifdef TARGET_I386 s->irq_coalesced = 0; #endif qemu_del_timer(s->periodic_timer); } } static void rtc_periodic_timer(void *opaque) { RTCState *s = opaque; rtc_timer_update(s, s->next_periodic_time); #ifdef TARGET_I386 if ((s->cmos_data[RTC_REG_C] & 0xc0) && rtc_td_hack) { s->irq_coalesced++; return; } #endif s->cmos_data[RTC_REG_C] |= 0xc0; rtc_irq_raise(s->irq); }
static void rtc_notify_clock_reset(Notifier *notifier, void *data) { RTCState *s = container_of(notifier, RTCState, clock_reset_notifier); int64_t now = *(int64_t *)data; rtc_set_date_from_host(&s->dev); s->next_second_time = now + (get_ticks_per_sec() * 99) / 100; qemu_mod_timer(s->second_timer2, s->next_second_time); rtc_timer_update(s, now); #ifdef TARGET_I386 if (rtc_td_hack) { rtc_coalesced_timer_update(s); } #endif }
// Lua: tmr.time() , return rtc time in second static int tmr_time( lua_State* L ){ uint64_t us=rtc_timer_update(false); lua_pushinteger(L, us/1000000); return 1; }
static int rtc_ioport_write(void *opaque, uint32_t addr, uint32_t data) { RTCState *s = opaque; struct domain *d = vrtc_domain(s); uint32_t orig; spin_lock(&s->lock); if ( (addr & 1) == 0 ) { data &= 0x7f; s->hw.cmos_index = data; spin_unlock(&s->lock); return (data < RTC_CMOS_SIZE); } if ( s->hw.cmos_index >= RTC_CMOS_SIZE ) { spin_unlock(&s->lock); return 0; } orig = s->hw.cmos_data[s->hw.cmos_index]; switch ( s->hw.cmos_index ) { case RTC_SECONDS_ALARM: case RTC_MINUTES_ALARM: case RTC_HOURS_ALARM: s->hw.cmos_data[s->hw.cmos_index] = data; alarm_timer_update(s); break; 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 in set mode, just write the register */ if ( (s->hw.cmos_data[RTC_REG_B] & RTC_SET) ) s->hw.cmos_data[s->hw.cmos_index] = data; else { /* Fetch the current time and update just this field. */ s->current_tm = gmtime(get_localtime(d)); rtc_copy_date(s); s->hw.cmos_data[s->hw.cmos_index] = data; rtc_set_time(s); } alarm_timer_update(s); break; case RTC_REG_A: /* UIP bit is read only */ s->hw.cmos_data[RTC_REG_A] = (data & ~RTC_UIP) | (orig & RTC_UIP); if ( (data ^ orig) & ~RTC_UIP ) rtc_timer_update(s); break; case RTC_REG_B: if ( data & RTC_SET ) { /* set mode: reset UIP mode */ s->hw.cmos_data[RTC_REG_A] &= ~RTC_UIP; /* adjust cmos before stopping */ if (!(orig & RTC_SET)) { s->current_tm = gmtime(get_localtime(d)); rtc_copy_date(s); } } else { /* if disabling set mode, update the time */ if ( orig & RTC_SET ) rtc_set_time(s); } check_for_pf_ticks(s); s->hw.cmos_data[RTC_REG_B] = data; /* * If the interrupt is already set when the interrupt becomes * enabled, raise an interrupt immediately. */ rtc_update_irq(s); if ( (data ^ orig) & RTC_PIE ) { TRACE_0D(TRC_HVM_EMUL_RTC_STOP_TIMER); destroy_periodic_time(&s->pt); s->period = 0; rtc_timer_update(s); } if ( (data ^ orig) & RTC_SET ) check_update_timer(s); if ( (data ^ orig) & (RTC_24H | RTC_DM_BINARY | RTC_SET) ) alarm_timer_update(s); break; case RTC_REG_C: case RTC_REG_D: /* cannot write to them */ break; } spin_unlock(&s->lock); return 1; }
static int rtc_ioport_write(void *opaque, uint32_t addr, uint32_t data) { RTCState *s = opaque; struct domain *d = vrtc_domain(s); uint32_t orig; spin_lock(&s->lock); if ( (addr & 1) == 0 ) { data &= 0x7f; s->hw.cmos_index = data; spin_unlock(&s->lock); return (data < RTC_CMOS_SIZE); } if ( s->hw.cmos_index >= RTC_CMOS_SIZE ) { spin_unlock(&s->lock); return 0; } orig = s->hw.cmos_data[s->hw.cmos_index]; switch ( s->hw.cmos_index ) { case RTC_SECONDS_ALARM: case RTC_MINUTES_ALARM: case RTC_HOURS_ALARM: s->hw.cmos_data[s->hw.cmos_index] = data; alarm_timer_update(s); break; 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: s->hw.cmos_data[s->hw.cmos_index] = data; /* if in set mode, do not update the time */ if ( !(s->hw.cmos_data[RTC_REG_B] & RTC_SET) ) rtc_set_time(s); alarm_timer_update(s); break; case RTC_REG_A: /* UIP bit is read only */ s->hw.cmos_data[RTC_REG_A] = (data & ~RTC_UIP) | (orig & RTC_UIP); if ( (data ^ orig) & ~RTC_UIP ) rtc_timer_update(s); break; case RTC_REG_B: if ( data & RTC_SET ) { /* set mode: reset UIP mode */ s->hw.cmos_data[RTC_REG_A] &= ~RTC_UIP; /* adjust cmos before stopping */ if (!(s->hw.cmos_data[RTC_REG_B] & RTC_SET)) { s->current_tm = gmtime(get_localtime(d)); rtc_copy_date(s); } } else { /* if disabling set mode, update the time */ if ( s->hw.cmos_data[RTC_REG_B] & RTC_SET ) rtc_set_time(s); } /* if the interrupt is already set when the interrupt become * enabled, raise an interrupt immediately*/ if ((data & RTC_UIE) && !(s->hw.cmos_data[RTC_REG_B] & RTC_UIE)) if (s->hw.cmos_data[RTC_REG_C] & RTC_UF) { hvm_isa_irq_deassert(d, RTC_IRQ); hvm_isa_irq_assert(d, RTC_IRQ); } s->hw.cmos_data[RTC_REG_B] = data; if ( (data ^ orig) & RTC_PIE ) rtc_timer_update(s); check_update_timer(s); alarm_timer_update(s); break; case RTC_REG_C: case RTC_REG_D: /* cannot write to them */ break; } spin_unlock(&s->lock); return 1; }