int domain_vtimer_init(struct domain *d, struct xen_arch_domainconfig *config)
{
- d->arch.phys_timer_base.offset = NOW();
d->arch.virt_timer_base.offset = READ_SYSREG64(CNTPCT_EL0);
d->time_offset.seconds = ticks_to_ns(d->arch.virt_timer_base.offset - boot_count);
do_div(d->time_offset.seconds, 1000000000);
init_timer(&t->timer, phys_timer_expired, t, v->processor);
t->ctl = 0;
- t->cval = NOW();
t->irq = d0
? timer_get_irq(TIMER_PHYS_NONSECURE_PPI)
: GUEST_TIMER_PHYS_NS_PPI;
static bool vtimer_cntp_ctl(struct cpu_user_regs *regs, uint32_t *r, bool read)
{
struct vcpu *v = current;
+ s_time_t expires;
if ( !ACCESS_ALLOWED(regs, EL0PTEN) )
return false;
if ( v->arch.phys_timer.ctl & CNTx_CTL_ENABLE )
{
- set_timer(&v->arch.phys_timer.timer,
- v->arch.phys_timer.cval + v->domain->arch.phys_timer_base.offset);
+ /*
+ * If cval is before the point Xen started, expire timer
+ * immediately.
+ */
+ expires = v->arch.phys_timer.cval > boot_count
+ ? ticks_to_ns(v->arch.phys_timer.cval - boot_count) : 0;
+ set_timer(&v->arch.phys_timer.timer, expires);
}
else
stop_timer(&v->arch.phys_timer.timer);
bool read)
{
struct vcpu *v = current;
- s_time_t now;
+ uint64_t cntpct;
+ s_time_t expires;
if ( !ACCESS_ALLOWED(regs, EL0PTEN) )
return false;
- now = NOW() - v->domain->arch.phys_timer_base.offset;
+ cntpct = get_cycles();
if ( read )
{
- *r = (uint32_t)(ns_to_ticks(v->arch.phys_timer.cval - now) & 0xffffffffull);
+ *r = (uint32_t)((v->arch.phys_timer.cval - cntpct) & 0xffffffffull);
}
else
{
- v->arch.phys_timer.cval = now + ticks_to_ns(*r);
+ v->arch.phys_timer.cval = cntpct + *r;
if ( v->arch.phys_timer.ctl & CNTx_CTL_ENABLE )
{
v->arch.phys_timer.ctl &= ~CNTx_CTL_PENDING;
- set_timer(&v->arch.phys_timer.timer,
- v->arch.phys_timer.cval +
- v->domain->arch.phys_timer_base.offset);
+ /*
+ * If cval is before the point Xen started, expire timer
+ * immediately.
+ */
+ expires = v->arch.phys_timer.cval > boot_count
+ ? ticks_to_ns(v->arch.phys_timer.cval - boot_count) : 0;
+ set_timer(&v->arch.phys_timer.timer, expires);
}
}
return true;
bool read)
{
struct vcpu *v = current;
+ s_time_t expires;
if ( !ACCESS_ALLOWED(regs, EL0PTEN) )
return false;
if ( read )
{
- *r = ns_to_ticks(v->arch.phys_timer.cval);
+ *r = v->arch.phys_timer.cval;
}
else
{
- v->arch.phys_timer.cval = ticks_to_ns(*r);
+ v->arch.phys_timer.cval = *r;
if ( v->arch.phys_timer.ctl & CNTx_CTL_ENABLE )
{
v->arch.phys_timer.ctl &= ~CNTx_CTL_PENDING;
- set_timer(&v->arch.phys_timer.timer,
- v->arch.phys_timer.cval +
- v->domain->arch.phys_timer_base.offset);
+ /*
+ * If cval is before the point Xen started, expire timer
+ * immediately.
+ */
+ expires = v->arch.phys_timer.cval > boot_count
+ ? ticks_to_ns(v->arch.phys_timer.cval - boot_count) : 0;
+ set_timer(&v->arch.phys_timer.timer, expires);
}
}
return true;