On 6/21/19 10:38 AM, Marc Zyngier wrote: > Add the required handling for EL2 and EL02 registers, as > well as EL1 registers used in the E2H context. > > Signed-off-by: Marc Zyngier <marc.zyngier@xxxxxxx> > --- > arch/arm64/kvm/sys_regs.c | 72 +++++++++++++++++++++++++++++++++++++++ > 1 file changed, 72 insertions(+) > > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c > index ba3bcd29c02d..0bd6a66b621e 100644 > --- a/arch/arm64/kvm/sys_regs.c > +++ b/arch/arm64/kvm/sys_regs.c > @@ -1361,20 +1361,92 @@ static bool access_arch_timer(struct kvm_vcpu *vcpu, > > switch (reg) { > case SYS_CNTP_TVAL_EL0: > + if (vcpu_mode_el2(vcpu) && vcpu_el2_e2h_is_set(vcpu)) > + tmr = TIMER_HPTIMER; > + else > + tmr = TIMER_PTIMER; > + treg = TIMER_REG_TVAL; > + break; > + > case SYS_AARCH32_CNTP_TVAL: > + case SYS_CNTP_TVAL_EL02: > tmr = TIMER_PTIMER; > treg = TIMER_REG_TVAL; > break; > + > + case SYS_CNTV_TVAL_EL02: > + tmr = TIMER_VTIMER; > + treg = TIMER_REG_TVAL; > + break; > + > + case SYS_CNTHP_TVAL_EL2: > + tmr = TIMER_HPTIMER; > + treg = TIMER_REG_TVAL; > + break; > + > + case SYS_CNTHV_TVAL_EL2: > + tmr = TIMER_HVTIMER; > + treg = TIMER_REG_TVAL; > + break; > + > case SYS_CNTP_CTL_EL0: > + if (vcpu_mode_el2(vcpu) && vcpu_el2_e2h_is_set(vcpu)) > + tmr = TIMER_HPTIMER; > + else > + tmr = TIMER_PTIMER; > + treg = TIMER_REG_CTL; > + break; > + > case SYS_AARCH32_CNTP_CTL: > + case SYS_CNTP_CTL_EL02: > tmr = TIMER_PTIMER; > treg = TIMER_REG_CTL; > break; > + > + case SYS_CNTV_CTL_EL02: > + tmr = TIMER_VTIMER; > + treg = TIMER_REG_CTL; > + break; > + > + case SYS_CNTHP_CTL_EL2: > + tmr = TIMER_HPTIMER; > + treg = TIMER_REG_CTL; > + break; > + > + case SYS_CNTHV_CTL_EL2: > + tmr = TIMER_HVTIMER; > + treg = TIMER_REG_CTL; > + break; > + > case SYS_CNTP_CVAL_EL0: > + if (vcpu_mode_el2(vcpu) && vcpu_el2_e2h_is_set(vcpu)) > + tmr = TIMER_HPTIMER; > + else > + tmr = TIMER_PTIMER; > + treg = TIMER_REG_CVAL; > + break; > + > case SYS_AARCH32_CNTP_CVAL: > + case SYS_CNTP_CVAL_EL02: > tmr = TIMER_PTIMER; > treg = TIMER_REG_CVAL; > break; > + > + case SYS_CNTV_CVAL_EL02: > + tmr = TIMER_VTIMER; > + treg = TIMER_REG_CVAL; > + break; > + > + case SYS_CNTHP_CVAL_EL2: > + tmr = TIMER_HPTIMER; > + treg = TIMER_REG_CVAL; > + break; > + > + case SYS_CNTHV_CVAL_EL2: > + tmr = TIMER_HVTIMER; > + treg = TIMER_REG_CVAL; > + break; > + > case SYS_CNTVOFF_EL2: > tmr = TIMER_VTIMER; > treg = TIMER_REG_VOFF; Shouldn't we forward physical timer traps to the L1 guest hypervisor if __vcpu_sys_reg(vcpu, CNTHCTL_EL2.EL1PTEN) == 0 (trap access) and !vcpu_mode_el2(vcpu)? A regular (non-nested) non-vhe hypervisor can set that bit to emulate the physical timer. If I remember correctly, KVM with VHE used to do it too until some time ago.