/* Set the timer to wake us up at a particular time. * Timeout is a Xen system time (nanoseconds since boot); 0 disables the timer. * Returns 1 on success; 0 if the timeout is too soon or is in the past. */ int reprogram_timer(s_time_t timeout) { uint64_t deadline; if ( timeout == 0 ) { #if USE_HYP_TIMER WRITE_SYSREG32(0, CNTHP_CTL_EL2); #else WRITE_SYSREG32(0, CNTP_CTL_EL0); #endif return 1; } deadline = ns_to_ticks(timeout) + boot_count; #if USE_HYP_TIMER WRITE_SYSREG64(deadline, CNTHP_CVAL_EL2); WRITE_SYSREG32(CNTx_CTL_ENABLE, CNTHP_CTL_EL2); #else WRITE_SYSREG64(deadline, CNTP_CVAL_EL0); WRITE_SYSREG32(CNTx_CTL_ENABLE, CNTP_CTL_EL0); #endif isb(); /* No need to check for timers in the past; the Generic Timer fires * on a signed 63-bit comparison. */ return 1; }
static int vtimer_cntp_tval(struct cpu_user_regs *regs, uint32_t *r, int read) { struct vcpu *v = current; s_time_t now; if ( !ACCESS_ALLOWED(regs, EL0PTEN) ) return 0; now = NOW() - v->domain->arch.phys_timer_base.offset; if ( read ) { *r = (uint32_t)(ns_to_ticks(v->arch.phys_timer.cval - now) & 0xffffffffull); } else { v->arch.phys_timer.cval = now + ticks_to_ns(*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); } } return 1; }
static bool vtimer_cntp_cval(struct cpu_user_regs *regs, uint64_t *r, bool read) { struct vcpu *v = current; if ( !ACCESS_ALLOWED(regs, EL0PTEN) ) return false; if ( read ) { *r = ns_to_ticks(v->arch.phys_timer.cval); } else { v->arch.phys_timer.cval = ticks_to_ns(*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); } } return true; }
static int vtimer_emulate_32(struct cpu_user_regs *regs, union hsr hsr) { struct vcpu *v = current; struct hsr_cp32 cp32 = hsr.cp32; uint32_t *r = (uint32_t *)select_user_reg(regs, cp32.reg); s_time_t now; switch ( hsr.bits & HSR_CP32_REGS_MASK ) { case HSR_CPREG32(CNTP_CTL): if ( cp32.read ) { *r = v->arch.phys_timer.ctl; } else { uint32_t ctl = *r & ~CNTx_CTL_PENDING; if ( ctl & CNTx_CTL_ENABLE ) ctl |= v->arch.phys_timer.ctl & CNTx_CTL_PENDING; v->arch.phys_timer.ctl = ctl; 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); } else stop_timer(&v->arch.phys_timer.timer); } return 1; case HSR_CPREG32(CNTP_TVAL): now = NOW() - v->domain->arch.phys_timer_base.offset; if ( cp32.read ) { *r = (uint32_t)(ns_to_ticks(v->arch.phys_timer.cval - now) & 0xffffffffull); } else { v->arch.phys_timer.cval = now + ticks_to_ns(*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); } } return 1; default: return 0; } }
static int vtimer_cntpct(struct cpu_user_regs *regs, uint64_t *r, int read) { struct vcpu *v = current; uint64_t ticks; s_time_t now; if ( read ) { now = NOW() - v->domain->arch.phys_timer_base.offset; ticks = ns_to_ticks(now); *r = ticks; return 1; } else { gdprintk(XENLOG_DEBUG, "WRITE to R/O CNTPCT\n"); return 0; } }
static int vtimer_emulate_64(struct cpu_user_regs *regs, union hsr hsr) { struct vcpu *v = current; struct hsr_cp64 cp64 = hsr.cp64; uint32_t *r1 = (uint32_t *)select_user_reg(regs, cp64.reg1); uint32_t *r2 = (uint32_t *)select_user_reg(regs, cp64.reg2); uint64_t ticks; s_time_t now; switch ( hsr.bits & HSR_CP64_REGS_MASK ) { case HSR_CPREG64(CNTPCT): if ( cp64.read ) { now = NOW() - v->arch.phys_timer.offset; ticks = ns_to_ticks(now); *r1 = (uint32_t)(ticks & 0xffffffff); *r2 = (uint32_t)(ticks >> 32); return 1; } else {