summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYong-Xuan Wang <yongxuan.wang@sifive.com>2026-07-21 22:52:02 -0700
committerAnup Patel <anup@brainfault.org>2026-08-08 19:18:11 +0530
commitdfdf1374fdeccb5b7e3d35186228e01ec5ea5f01 (patch)
tree40833cf0b0067f23f513c0f8911a08169faf5b49
parent735bc20c24187ca419c9d5e63860a54b91be34bd (diff)
downloadlinux-dfdf1374fdeccb5b7e3d35186228e01ec5ea5f01.tar.gz
linux-dfdf1374fdeccb5b7e3d35186228e01ec5ea5f01.zip
KVM: RISC-V: Clear former VCPU cache on virtualization disable
When a CPU is taken offline or enters deep idle states, hypervisor CSR state is lost. The kvm_former_vcpu fast-path optimization caches the last VCPU that ran on each CPU to avoid expensive CSR restoration when the same VCPU is re-scheduled on the same CPU. However, if this cache is not cleared when CSR state is lost, the next VCPU entry will incorrectly skip CSR restoration, leading to corrupt hypervisor state. Add kvm_riscv_clear_former_vcpu() to invalidate the per-CPU cache and call it from kvm_arch_disable_virtualization_cpu() to ensure proper CSR restoration after CPU offline or system suspend events. Fixes: 1323a5cfe52c ("KVM: riscv: Skip CSR restore if VCPU is reloaded on the same core") Signed-off-by: Yong-Xuan Wang <yongxuan.wang@sifive.com> Reviewed-by: Nutty Liu <nutty.liu@hotmail.com> Reviewed-by: Anup Patel <anup@brainfault.org> Link: https://lore.kernel.org/r/20260721-kvm-cpu-pm-v4-1-146bf942547d@sifive.com Signed-off-by: Anup Patel <anup@brainfault.org>
-rw-r--r--arch/riscv/include/asm/kvm_host.h2
-rw-r--r--arch/riscv/kvm/main.c2
-rw-r--r--arch/riscv/kvm/vcpu.c11
3 files changed, 15 insertions, 0 deletions
diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h
index ba5e53e7962b..a30600579231 100644
--- a/arch/riscv/include/asm/kvm_host.h
+++ b/arch/riscv/include/asm/kvm_host.h
@@ -290,6 +290,8 @@ static inline bool kvm_arch_pmi_in_guest(struct kvm_vcpu *vcpu)
static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) {}
static inline void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) {}
+void kvm_riscv_clear_former_vcpu(void);
+
int kvm_riscv_setup_default_irq_routing(struct kvm *kvm, u32 lines);
void __kvm_riscv_unpriv_trap(void);
diff --git a/arch/riscv/kvm/main.c b/arch/riscv/kvm/main.c
index 0924c75100a2..350e4f097d6e 100644
--- a/arch/riscv/kvm/main.c
+++ b/arch/riscv/kvm/main.c
@@ -69,6 +69,8 @@ void kvm_arch_disable_virtualization_cpu(void)
csr_write(CSR_HEDELEG, 0);
csr_write(CSR_HIDELEG, 0);
+ kvm_riscv_clear_former_vcpu();
+
kvm_riscv_nacl_disable();
}
diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c
index 56dc0af2f9db..1b4416b20665 100644
--- a/arch/riscv/kvm/vcpu.c
+++ b/arch/riscv/kvm/vcpu.c
@@ -26,6 +26,17 @@
static DEFINE_PER_CPU(struct kvm_vcpu *, kvm_former_vcpu);
+void kvm_riscv_clear_former_vcpu(void)
+{
+ /*
+ * Clear the per-CPU former VCPU pointer because hypervisor CSR state
+ * will be lost. This ensures that the next VCPU entry will properly
+ * restore all CSRs instead of incorrectly skipping CSR restoration
+ * via the fast-path optimization.
+ */
+ __this_cpu_write(kvm_former_vcpu, NULL);
+}
+
const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {
KVM_GENERIC_VCPU_STATS(),
STATS_DESC_COUNTER(VCPU, ecall_exit_stat),