[PATCH] KVM: riscv: mirror VSTIMECMP into t->next_cycles in sstc path

Jun Sun jsun at junsun.net
Tue Jun 9 11:39:21 PDT 2026


update_vstimecmp writes the new target to the hardware-visible VSTIMECMP
CSR (via NACL shmem) but did not also update t->next_cycles.  Between
the SBI set_timer handler and the next guest entry, preemption can fire
(at preempt_enable after sync_interrupts, or via schedule() in
kvm_xfer_to_guest_mode_handle_work / kvm_riscv_check_vcpu_requests).
When the vCPU is reloaded, kvm_arch_vcpu_load -> kvm_riscv_vcpu_timer_restore
writes ncsr_write(VSTIMECMP, t->next_cycles), which clobbers the fresh
shmem value with a stale t->next_cycles from a prior iteration.  The
guest then resumes with VSTIMECMP set to an old far-future value;
hardware never asserts VSTIP; the guest's timer ISR never runs; boot
wedges with riscv-timer counter frozen.

Without the fix AOSP/cuttlefish stalls on K3 + crosvm: guest /proc/interrupts
riscv-timer counter frozen indefinitely while /proc/uptime keeps climbing.
With the fix AOSP/cuttlefish boots up fine.

Mirror the value into t->next_cycles next to the ncsr_write, matching
what kvm_riscv_vcpu_update_hrtimer already does for the non-sstc path.
---
 arch/riscv/kvm/vcpu_timer.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/riscv/kvm/vcpu_timer.c b/arch/riscv/kvm/vcpu_timer.c
index 85a7262115e1..4e31a6a341c5 100644
--- a/arch/riscv/kvm/vcpu_timer.c
+++ b/arch/riscv/kvm/vcpu_timer.c
@@ -71,6 +71,15 @@ 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)
 {
+	/*
+	 * Mirror kvm_riscv_vcpu_update_hrtimer (the non-sstc path):
+	 * update t->next_cycles, and then set hw CSR_VSTIMECMP.
+	 * Otherwise, a race condition with preemption can cause
+	 * CSR_VSTIMECMP to end up holding a stale value
+	 * (kvm_riscv_vcpu_timer_restore writes the old t->next_cycles
+	 * back into VSTIMECMP shmem on sched-in).
+	 */
+	vcpu->arch.timer.next_cycles = ncycles;
 #if defined(CONFIG_32BIT)
 	ncsr_write(CSR_VSTIMECMP, ncycles & 0xFFFFFFFF);
 	ncsr_write(CSR_VSTIMECMPH, ncycles >> 32);
-- 
2.34.1




More information about the linux-riscv mailing list