[PATCH] KVM: arm64: Fix hvhe and broken CNTVOFF_EL2
Yao Yuan
yaoyuan at linux.alibaba.com
Thu Aug 6 18:37:06 PDT 2026
On Thu, Aug 06, 2026 at 03:01:05PM +0800, Mostafa Saleh wrote:
> When running on a setup affected with broken CNTVOFF_EL2
> (has_broken_cntvoff())
>
> Booting with VHE or protected mode(nvhe) (id_aa64mmfr1.vh=0
> and arm64_sw.hvhe=0) works fine.
>
> However launching a protected VM with protected hvhe mode panics the
> guest kernel:
...
> And for non protected VMs seems to hang or progress really slowly.
>
> The workaround avoids setting non-zero CNTVOFF_EL2 and trapping the
> virtual counter to emulate the offset.
> In the VHE path (timer_set_traps()), traps are only enabled when the
> guest actually has a non-zero virtual timer offset.
> However, __timer_enable_traps() in hyp/nvhe/timer-sr.c unconditionally
> set CNTHCTL_EL1TVT and CNTHCTL_EL1TVCT whenever has_broken_cntvoff()
> was true.
>
> Which causes 2 issues:
> 1) Protected VMs: kvm_handle_pvm_sysreg() does not find "cntv_ctl_el0"
> in pvm_sys_reg_descs and injects undefined instruction exceptions.
>
> 2) non-protected guests are trapped all the time even with offset of
> zero.
>
> Fix this by adding a check in __timer_enable_traps() similar to the one in
> timer_set_traps()
Hi Saleh,
May more fix is needed for case that guest real have virtual
offset, due to no cntv_ctl_el0 handler there. For current
fix for virtual offset is zero:
Reviewed-by: Yuan Yao <yaoyuan at linux.alibaba.com>
>
> Fixes: 0bc9a9e85fcf ("KVM: arm64: Work around x1e's CNTVOFF_EL2 bogosity")
> Signed-off-by: Mostafa Saleh <smostafa at google.com>
> ---
> arch/arm64/kvm/hyp/nvhe/timer-sr.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm64/kvm/hyp/nvhe/timer-sr.c b/arch/arm64/kvm/hyp/nvhe/timer-sr.c
> index ff176f4ce7de..98b6e37ee8fa 100644
> --- a/arch/arm64/kvm/hyp/nvhe/timer-sr.c
> +++ b/arch/arm64/kvm/hyp/nvhe/timer-sr.c
> @@ -10,6 +10,7 @@
>
> #include <asm/kvm_hyp.h>
> #include <asm/kvm_mmu.h>
> +#include <hyp/switch.h>
>
> void __kvm_timer_set_cntvoff(u64 cntvoff)
> {
> @@ -63,7 +64,7 @@ void __timer_enable_traps(struct kvm_vcpu *vcpu)
> * Trap the virtual counter/timer if we have a broken cntvoff
> * implementation.
> */
> - if (has_broken_cntvoff())
> + if (has_broken_cntvoff() && hyp_timer_get_offset(vcpu_vtimer(vcpu)))
> set |= CNTHCTL_EL1TVT | CNTHCTL_EL1TVCT;
>
> sysreg_clear_set(cnthctl_el2, clr, set);
> --
> 2.55.0.654.g21b8a5bc05-goog
>
More information about the linux-arm-kernel
mailing list