From be1849348b0d1c63deca60d36aa2caa5d6ae3abd Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 12 Oct 2021 17:46:25 +0100 Subject: [PATCH] ANDROID: KVM: arm64: Save/restore virtual timer state from the shadow vcpu Similar to the vgic state, make sure to sync and flush the virtual timer state between the host and the hyp shadow vCPU structs when running in nVHE protected mode. Signed-off-by: Marc Zyngier Bug: 209580772 Change-Id: Ib90273bb670d9d815dd9f542369dde00753655cf Signed-off-by: Will Deacon --- arch/arm64/kvm/arch_timer.c | 7 ++++++- arch/arm64/kvm/hyp/nvhe/hyp-main.c | 24 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c index 3df67c127489..b81944f25fc8 100644 --- a/arch/arm64/kvm/arch_timer.c +++ b/arch/arm64/kvm/arch_timer.c @@ -88,7 +88,9 @@ static u64 timer_get_offset(struct arch_timer_context *ctxt) switch(arch_timer_ctx_index(ctxt)) { case TIMER_VTIMER: - return __vcpu_sys_reg(vcpu, CNTVOFF_EL2); + if (likely(!kvm_vm_is_protected(vcpu->kvm))) + return __vcpu_sys_reg(vcpu, CNTVOFF_EL2); + fallthrough; default: return 0; } @@ -754,6 +756,9 @@ static void update_vtimer_cntvoff(struct kvm_vcpu *vcpu, u64 cntvoff) struct kvm *kvm = vcpu->kvm; struct kvm_vcpu *tmp; + if (unlikely(kvm_vm_is_protected(vcpu->kvm))) + cntvoff = 0; + mutex_lock(&kvm->lock); kvm_for_each_vcpu(i, tmp, kvm) timer_set_offset(vcpu_vtimer(tmp), cntvoff); diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c index a5bdee91344e..13870bc5d4d0 100644 --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c @@ -253,6 +253,28 @@ static void sync_vgic_state(struct kvm_vcpu *host_vcpu, host_cpu_if->vgic_lr[i] = shadow_cpu_if->vgic_lr[i]; } +static void flush_timer_state(struct kvm_vcpu *shadow_vcpu) +{ + /* + * A shadow vcpu has no offset, and sees vtime == ptime. The + * ptimer is fully emulated by EL1 and cannot be trusted. + */ + write_sysreg(0, cntvoff_el2); + isb(); + write_sysreg_el0(__vcpu_sys_reg(shadow_vcpu, CNTV_CVAL_EL0), SYS_CNTV_CVAL); + write_sysreg_el0(__vcpu_sys_reg(shadow_vcpu, CNTV_CTL_EL0), SYS_CNTV_CTL); +} + +static void sync_timer_state(struct kvm_vcpu *shadow_vcpu) +{ + /* + * Preserve the vtimer state so that it is always correct, + * even if the host tries to make a mess. + */ + __vcpu_sys_reg(shadow_vcpu, CNTV_CVAL_EL0) = read_sysreg_el0(SYS_CNTV_CVAL); + __vcpu_sys_reg(shadow_vcpu, CNTV_CTL_EL0) = read_sysreg_el0(SYS_CNTV_CTL); +} + static bool handle_shadow_entry(struct kvm_vcpu *shadow_vcpu) { struct kvm_vcpu *host_vcpu = shadow_vcpu->arch.pkvm.host_vcpu; @@ -260,6 +282,7 @@ static bool handle_shadow_entry(struct kvm_vcpu *shadow_vcpu) shadow_entry_exit_handler_fn ec_handler; flush_vgic_state(host_vcpu, shadow_vcpu); + flush_timer_state(shadow_vcpu); switch (ARM_EXCEPTION_CODE(shadow_vcpu->arch.pkvm.exit_code)) { case ARM_EXCEPTION_IRQ: @@ -286,6 +309,7 @@ static void handle_shadow_exit(struct kvm_vcpu *shadow_vcpu) shadow_entry_exit_handler_fn ec_handler; sync_vgic_state(host_vcpu, shadow_vcpu); + sync_timer_state(shadow_vcpu); switch (shadow_vcpu->arch.pkvm.exit_code) { case ARM_EXCEPTION_IRQ: