| RISC-V: KVM: update next_cycles in kvm_riscv_vcpu_update_vstimecmp()
|
|
|
| kvm_riscv_vcpu_update_vstimecmp() writes the guest's new timer compare
|
| value to CSR_VSTIMECMP but does not update t->next_cycles, unlike the
|
| hrtimer variant. t->next_cycles is only refreshed by
|
| kvm_riscv_vcpu_timer_sync() at VM-exit time, which runs before the SBI
|
| set_timer handler.
|
|
|
| If the vcpu is scheduled out or exits to userspace after handling an
|
| SBI set_timer call but before re-entering the guest,
|
| kvm_riscv_vcpu_timer_save() disarms the hardware (vstimecmp = -1UL,
|
| since 57f576e860d3) and kvm_riscv_vcpu_timer_restore() then restores
|
| the stale pre-SBI value, silently discarding the guest's armed timer.
|
|
|
| Guests arming their timer via SBI (e.g. OpenBSD/riscv64, which uses a
|
| one-shot design with no periodic fallback) lose their clock permanently
|
| within minutes under host load. Guests using Sstc directly are
|
| unaffected because timer_sync recaptures the hardware value at every
|
| exit.
|
|
|
| Fixes: 8f5cb44b1bae ("RISC-V: KVM: Support sstc extension")
|
|
|
| --- a/arch/riscv/kvm/vcpu_timer.c
|
| +++ b/arch/riscv/kvm/vcpu_timer.c
|
| @@ -71,6 +71,10 @@ static int kvm_riscv_vcpu_timer_cancel(struct kvm_vcpu_timer *t)
|
|
|
| static int kvm_riscv_vcpu_update_vstimecmp(struct kvm_vcpu *vcpu, u64 ncycles)
|
| {
|
| + struct kvm_vcpu_timer *t = &vcpu->arch.timer;
|
| +
|
| + t->next_cycles = ncycles;
|
| +
|
| #if defined(CONFIG_32BIT)
|
| ncsr_write(CSR_VSTIMECMP, ncycles & 0xFFFFFFFF);
|
| ncsr_write(CSR_VSTIMECMPH, ncycles >> 32);
|