static void hpet_set_timer(HPETState *h, unsigned int tn) { uint64_t tn_cmp, cur_tick, diff; unsigned int irq; unsigned int oneshot; ASSERT(tn < HPET_TIMER_NUM); ASSERT(spin_is_locked(&h->lock)); if ( (tn == 0) && (h->hpet.config & HPET_CFG_LEGACY) ) { /* HPET specification requires PIT shouldn't generate * interrupts if LegacyReplacementRoute is set for timer0 */ PITState *pit = &vhpet_domain(h)->arch.hvm_domain.pl_time.vpit; pit_stop_channel0_irq(pit); } if ( !timer_enabled(h, tn) ) return; tn_cmp = hpet_get_comparator(h, tn); cur_tick = hpet_read_maincounter(h); if ( timer_is_32bit(h, tn) ) { tn_cmp = (uint32_t)tn_cmp; cur_tick = (uint32_t)cur_tick; } diff = tn_cmp - cur_tick; /* * Detect time values set in the past. This is hard to do for 32-bit * comparators as the timer does not have to be set that far in the future * for the counter difference to wrap a 32-bit signed integer. We fudge * by looking for a 'small' time value in the past. */ if ( (int64_t)diff < 0 ) diff = (timer_is_32bit(h, tn) && (-diff > HPET_TINY_TIME_SPAN)) ? (uint32_t)diff : 0; if ( (tn <= 1) && (h->hpet.config & HPET_CFG_LEGACY) ) /* if LegacyReplacementRoute bit is set, HPET specification requires timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC, timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC. */ irq = (tn == 0) ? 0 : 8; else irq = timer_int_route(h, tn); /* * diff is the time from now when the timer should fire, for a periodic * timer we also need the period which may be different because time may * have elapsed between the time the comparator was written and the timer * being enabled (now). */ oneshot = !timer_is_periodic(h, tn); create_periodic_time(vhpet_vcpu(h), &h->pt[tn], hpet_tick_to_ns(h, diff), oneshot ? 0 : hpet_tick_to_ns(h, h->hpet.period[tn]), irq, NULL, NULL); }
static uint64_t hpet_get_comparator(HPETState *h, unsigned int tn) { uint64_t comparator; uint64_t elapsed; comparator = h->hpet.comparator64[tn]; if ( timer_is_periodic(h, tn) ) { /* update comparator by number of periods elapsed since last update */ uint64_t period = h->hpet.period[tn]; if (period) { elapsed = hpet_read_maincounter(h) + period - 1 - comparator; comparator += (elapsed / period) * period; h->hpet.comparator64[tn] = comparator; } } /* truncate if timer is in 32 bit mode */ if ( timer_is_32bit(h, tn) ) comparator = (uint32_t)comparator; h->hpet.timers[tn].cmp = comparator; return comparator; }