Skip to content

Commit 4bad306

Browse files
author
Marc Zyngier
committed
KVM: arm64: nv: Sync nested timer state with FEAT_NV2
Emulating the timers with FEAT_NV2 is a bit odd, as the timers can be reconfigured behind our back without the hypervisor even noticing. In the VHE case, that's an actual regression in the architecture... Co-developed-by: Christoffer Dall <[email protected]> Signed-off-by: Christoffer Dall <[email protected]> Acked-by: Oliver Upton <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Marc Zyngier <[email protected]>
1 parent b59dbb9 commit 4bad306

File tree

3 files changed

+48
-0
lines changed

3 files changed

+48
-0
lines changed

arch/arm64/kvm/arch_timer.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -905,6 +905,50 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
905905
kvm_timer_blocking(vcpu);
906906
}
907907

908+
void kvm_timer_sync_nested(struct kvm_vcpu *vcpu)
909+
{
910+
/*
911+
* When NV2 is on, guest hypervisors have their EL1 timer register
912+
* accesses redirected to the VNCR page. Any guest action taken on
913+
* the timer is postponed until the next exit, leading to a very
914+
* poor quality of emulation.
915+
*/
916+
if (!is_hyp_ctxt(vcpu))
917+
return;
918+
919+
if (!vcpu_el2_e2h_is_set(vcpu)) {
920+
/*
921+
* A non-VHE guest hypervisor doesn't have any direct access
922+
* to its timers: the EL2 registers trap (and the HW is
923+
* fully emulated), while the EL0 registers access memory
924+
* despite the access being notionally direct. Boo.
925+
*
926+
* We update the hardware timer registers with the
927+
* latest value written by the guest to the VNCR page
928+
* and let the hardware take care of the rest.
929+
*/
930+
write_sysreg_el0(__vcpu_sys_reg(vcpu, CNTV_CTL_EL0), SYS_CNTV_CTL);
931+
write_sysreg_el0(__vcpu_sys_reg(vcpu, CNTV_CVAL_EL0), SYS_CNTV_CVAL);
932+
write_sysreg_el0(__vcpu_sys_reg(vcpu, CNTP_CTL_EL0), SYS_CNTP_CTL);
933+
write_sysreg_el0(__vcpu_sys_reg(vcpu, CNTP_CVAL_EL0), SYS_CNTP_CVAL);
934+
} else {
935+
/*
936+
* For a VHE guest hypervisor, the EL2 state is directly
937+
* stored in the host EL1 timers, while the emulated EL0
938+
* state is stored in the VNCR page. The latter could have
939+
* been updated behind our back, and we must reset the
940+
* emulation of the timers.
941+
*/
942+
struct timer_map map;
943+
get_timer_map(vcpu, &map);
944+
945+
soft_timer_cancel(&map.emul_vtimer->hrtimer);
946+
soft_timer_cancel(&map.emul_ptimer->hrtimer);
947+
timer_emulate(map.emul_vtimer);
948+
timer_emulate(map.emul_ptimer);
949+
}
950+
}
951+
908952
/*
909953
* With a userspace irqchip we have to check if the guest de-asserted the
910954
* timer and if so, unmask the timer irq signal on the host interrupt

arch/arm64/kvm/arm.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1228,6 +1228,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
12281228
if (unlikely(!irqchip_in_kernel(vcpu->kvm)))
12291229
kvm_timer_sync_user(vcpu);
12301230

1231+
if (vcpu_has_nv(vcpu))
1232+
kvm_timer_sync_nested(vcpu);
1233+
12311234
kvm_arch_vcpu_ctxsync_fp(vcpu);
12321235

12331236
/*

include/kvm/arm_arch_timer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ int __init kvm_timer_hyp_init(bool has_gic);
9898
int kvm_timer_enable(struct kvm_vcpu *vcpu);
9999
void kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu);
100100
void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu);
101+
void kvm_timer_sync_nested(struct kvm_vcpu *vcpu);
101102
void kvm_timer_sync_user(struct kvm_vcpu *vcpu);
102103
bool kvm_timer_should_notify_user(struct kvm_vcpu *vcpu);
103104
void kvm_timer_update_run(struct kvm_vcpu *vcpu);

0 commit comments

Comments
 (0)