* [PATCH v7] KVM: riscv: Skip CSR restore if VCPU is reloaded on the same core
@ 2026-02-27 12:10 ` Jinyu Tang
0 siblings, 0 replies; 15+ messages in thread
From: Jinyu Tang @ 2026-02-27 12:10 UTC (permalink / raw)
To: Radim Krčmář, Anup Patel, Atish Patra,
Andrew Jones, Conor Dooley, Yong-Xuan Wang, Nutty Liu,
Paul Walmsley, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti
Cc: kvm, kvm-riscv, linux-riscv, linux-kernel, Jinyu Tang
Currently, kvm_arch_vcpu_load() unconditionally restores guest CSRs,
HGATP, and AIA state. However, when a VCPU is loaded back on the same
physical CPU, and no other KVM VCPU has run on this CPU since it was
last put, the hardware CSRs and AIA registers are still valid.
This patch optimizes the vcpu_load path by skipping the expensive CSR
and AIA writes if all the following conditions are met:
1. It is being reloaded on the same CPU (vcpu->arch.last_exit_cpu == cpu).
2. The CSRs are not dirty (!vcpu->arch.csr_dirty).
3. No other VCPU used this CPU (vcpu == __this_cpu_read(kvm_former_vcpu)).
To ensure this fast-path doesn't break corner cases:
- Live migration and VCPU reset are naturally safe. KVM initializes
last_exit_cpu to -1, which guarantees the fast-path won't trigger.
- The 'csr_dirty' flag tracks runtime userspace interventions. If
userspace modifies guest configurations (e.g., hedeleg via
KVM_SET_GUEST_DEBUG, or CSRs including AIA via KVM_SET_ONE_REG),
the flag is set to skip the fast path.
With the 'csr_dirty' safeguard proven effective, it is safe to
include kvm_riscv_vcpu_aia_load() inside the skip logic now.
Signed-off-by: Jinyu Tang <tjytimi@163.com>
---
v6 -> v7:
- Moved kvm_riscv_vcpu_aia_load() into the fast-path skip logic, as
suggested by Radim Krčmář.
- Verified the fix for the IMSIC instability issue reported in v3.
Testing was conducted on QEMU 10.0.2 with explicitly enabled AIA
(`-machine virt,aia=aplic-imsic`). The guest boots successfully
using virtio-mmio devices like virtio-blk and virtio-net.
v5 -> v6:
As suggested by Andrew Jones, checking 'last_exit_cpu' first (most
likely to fail on busy hosts) and placing the expensive
__this_cpu_read() last, skipping __this_cpu_write() in kvm_arch_vcpu_put()
if kvm_former_vcpu is already set to the current VCPU.
v4 -> v5:
- Dropped the 'vcpu->scheduled_out' check as Andrew Jones pointed out,
relying on 'last_exit_cpu', 'former_vcpu', and '!csr_dirty'
is sufficient and safe. This expands the optimization to cover many
userspace exits (e.g., MMIO) as well.
- Added a block comment in kvm_arch_vcpu_load() to warn future
developers about maintaining the 'csr_dirty' dependency, as Andrew's
suggestion to reduce fragility.
- Removed unnecessary single-line comments and fixed indentation nits.
v3 -> v4:
- Addressed Anup Patel's review regarding hardware state inconsistency.
- Introduced 'csr_dirty' flag to track dynamic userspace CSR/CONFIG
modifications (KVM_SET_ONE_REG, KVM_SET_GUEST_DEBUG), forcing a full
restore when debugging or modifying states at userspace.
- Kept kvm_riscv_vcpu_aia_load() out of the skip block to resolve IMSIC
VS-file instability.
v2 -> v3:
v2 was missing a critical check because I generated the patch from my
wrong (experimental) branch. This is fixed in v3. Sorry for my trouble.
v1 -> v2:
Apply the logic to aia csr load. Thanks for Andrew Jones's advice.
---
arch/riscv/include/asm/kvm_host.h | 3 +++
arch/riscv/kvm/vcpu.c | 24 ++++++++++++++++++++++--
arch/riscv/kvm/vcpu_onereg.c | 2 ++
3 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h
index 24585304c..7ee47b83c 100644
--- a/arch/riscv/include/asm/kvm_host.h
+++ b/arch/riscv/include/asm/kvm_host.h
@@ -273,6 +273,9 @@ struct kvm_vcpu_arch {
/* 'static' configurations which are set only once */
struct kvm_vcpu_config cfg;
+ /* Indicates modified guest CSRs */
+ bool csr_dirty;
+
/* SBI steal-time accounting */
struct {
gpa_t shmem;
diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c
index a55a95da5..2e4dfff07 100644
--- a/arch/riscv/kvm/vcpu.c
+++ b/arch/riscv/kvm/vcpu.c
@@ -24,6 +24,8 @@
#define CREATE_TRACE_POINTS
#include "trace.h"
+static DEFINE_PER_CPU(struct kvm_vcpu *, kvm_former_vcpu);
+
const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
KVM_GENERIC_VCPU_STATS(),
STATS_DESC_COUNTER(VCPU, ecall_exit_stat),
@@ -537,6 +539,8 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
vcpu->arch.cfg.hedeleg |= BIT(EXC_BREAKPOINT);
}
+ vcpu->arch.csr_dirty = true;
+
return 0;
}
@@ -581,6 +585,21 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
struct kvm_vcpu_config *cfg = &vcpu->arch.cfg;
+ /*
+ * If VCPU is being reloaded on the same physical CPU and no
+ * other KVM VCPU has run on this CPU since it was last put,
+ * we can skip the expensive CSR and HGATP writes.
+ *
+ * Note: If a new CSR is added to this fast-path skip block,
+ * make sure that 'csr_dirty' is set to true in any
+ * ioctl (e.g., KVM_SET_ONE_REG) that modifies it.
+ */
+ if (vcpu != __this_cpu_read(kvm_former_vcpu))
+ __this_cpu_write(kvm_former_vcpu, vcpu);
+ else if (vcpu->arch.last_exit_cpu == cpu && !vcpu->arch.csr_dirty)
+ goto csr_restore_done;
+
+ vcpu->arch.csr_dirty = false;
if (kvm_riscv_nacl_sync_csr_available()) {
nsh = nacl_shmem();
nacl_csr_write(nsh, CSR_VSSTATUS, csr->vsstatus);
@@ -624,6 +643,9 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
kvm_riscv_mmu_update_hgatp(vcpu);
+ kvm_riscv_vcpu_aia_load(vcpu, cpu);
+
+csr_restore_done:
kvm_riscv_vcpu_timer_restore(vcpu);
kvm_riscv_vcpu_host_fp_save(&vcpu->arch.host_context);
@@ -633,8 +655,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
kvm_riscv_vcpu_guest_vector_restore(&vcpu->arch.guest_context,
vcpu->arch.isa);
- kvm_riscv_vcpu_aia_load(vcpu, cpu);
-
kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu);
vcpu->cpu = cpu;
diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c
index e7ab6cb00..fc08bf833 100644
--- a/arch/riscv/kvm/vcpu_onereg.c
+++ b/arch/riscv/kvm/vcpu_onereg.c
@@ -652,6 +652,8 @@ static int kvm_riscv_vcpu_set_reg_csr(struct kvm_vcpu *vcpu,
if (rc)
return rc;
+ vcpu->arch.csr_dirty = true;
+
return 0;
}
--
2.43.0
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v7] KVM: riscv: Skip CSR restore if VCPU is reloaded on the same core
@ 2026-02-27 12:10 ` Jinyu Tang
0 siblings, 0 replies; 15+ messages in thread
From: Jinyu Tang @ 2026-02-27 12:10 UTC (permalink / raw)
To: Radim Krčmář, Anup Patel, Atish Patra,
Andrew Jones, Conor Dooley, Yong-Xuan Wang, Nutty Liu,
Paul Walmsley, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti
Cc: kvm, kvm-riscv, linux-riscv, linux-kernel, Jinyu Tang
Currently, kvm_arch_vcpu_load() unconditionally restores guest CSRs,
HGATP, and AIA state. However, when a VCPU is loaded back on the same
physical CPU, and no other KVM VCPU has run on this CPU since it was
last put, the hardware CSRs and AIA registers are still valid.
This patch optimizes the vcpu_load path by skipping the expensive CSR
and AIA writes if all the following conditions are met:
1. It is being reloaded on the same CPU (vcpu->arch.last_exit_cpu == cpu).
2. The CSRs are not dirty (!vcpu->arch.csr_dirty).
3. No other VCPU used this CPU (vcpu == __this_cpu_read(kvm_former_vcpu)).
To ensure this fast-path doesn't break corner cases:
- Live migration and VCPU reset are naturally safe. KVM initializes
last_exit_cpu to -1, which guarantees the fast-path won't trigger.
- The 'csr_dirty' flag tracks runtime userspace interventions. If
userspace modifies guest configurations (e.g., hedeleg via
KVM_SET_GUEST_DEBUG, or CSRs including AIA via KVM_SET_ONE_REG),
the flag is set to skip the fast path.
With the 'csr_dirty' safeguard proven effective, it is safe to
include kvm_riscv_vcpu_aia_load() inside the skip logic now.
Signed-off-by: Jinyu Tang <tjytimi@163.com>
---
v6 -> v7:
- Moved kvm_riscv_vcpu_aia_load() into the fast-path skip logic, as
suggested by Radim Krčmář.
- Verified the fix for the IMSIC instability issue reported in v3.
Testing was conducted on QEMU 10.0.2 with explicitly enabled AIA
(`-machine virt,aia=aplic-imsic`). The guest boots successfully
using virtio-mmio devices like virtio-blk and virtio-net.
v5 -> v6:
As suggested by Andrew Jones, checking 'last_exit_cpu' first (most
likely to fail on busy hosts) and placing the expensive
__this_cpu_read() last, skipping __this_cpu_write() in kvm_arch_vcpu_put()
if kvm_former_vcpu is already set to the current VCPU.
v4 -> v5:
- Dropped the 'vcpu->scheduled_out' check as Andrew Jones pointed out,
relying on 'last_exit_cpu', 'former_vcpu', and '!csr_dirty'
is sufficient and safe. This expands the optimization to cover many
userspace exits (e.g., MMIO) as well.
- Added a block comment in kvm_arch_vcpu_load() to warn future
developers about maintaining the 'csr_dirty' dependency, as Andrew's
suggestion to reduce fragility.
- Removed unnecessary single-line comments and fixed indentation nits.
v3 -> v4:
- Addressed Anup Patel's review regarding hardware state inconsistency.
- Introduced 'csr_dirty' flag to track dynamic userspace CSR/CONFIG
modifications (KVM_SET_ONE_REG, KVM_SET_GUEST_DEBUG), forcing a full
restore when debugging or modifying states at userspace.
- Kept kvm_riscv_vcpu_aia_load() out of the skip block to resolve IMSIC
VS-file instability.
v2 -> v3:
v2 was missing a critical check because I generated the patch from my
wrong (experimental) branch. This is fixed in v3. Sorry for my trouble.
v1 -> v2:
Apply the logic to aia csr load. Thanks for Andrew Jones's advice.
---
arch/riscv/include/asm/kvm_host.h | 3 +++
arch/riscv/kvm/vcpu.c | 24 ++++++++++++++++++++++--
arch/riscv/kvm/vcpu_onereg.c | 2 ++
3 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h
index 24585304c..7ee47b83c 100644
--- a/arch/riscv/include/asm/kvm_host.h
+++ b/arch/riscv/include/asm/kvm_host.h
@@ -273,6 +273,9 @@ struct kvm_vcpu_arch {
/* 'static' configurations which are set only once */
struct kvm_vcpu_config cfg;
+ /* Indicates modified guest CSRs */
+ bool csr_dirty;
+
/* SBI steal-time accounting */
struct {
gpa_t shmem;
diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c
index a55a95da5..2e4dfff07 100644
--- a/arch/riscv/kvm/vcpu.c
+++ b/arch/riscv/kvm/vcpu.c
@@ -24,6 +24,8 @@
#define CREATE_TRACE_POINTS
#include "trace.h"
+static DEFINE_PER_CPU(struct kvm_vcpu *, kvm_former_vcpu);
+
const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
KVM_GENERIC_VCPU_STATS(),
STATS_DESC_COUNTER(VCPU, ecall_exit_stat),
@@ -537,6 +539,8 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
vcpu->arch.cfg.hedeleg |= BIT(EXC_BREAKPOINT);
}
+ vcpu->arch.csr_dirty = true;
+
return 0;
}
@@ -581,6 +585,21 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
struct kvm_vcpu_config *cfg = &vcpu->arch.cfg;
+ /*
+ * If VCPU is being reloaded on the same physical CPU and no
+ * other KVM VCPU has run on this CPU since it was last put,
+ * we can skip the expensive CSR and HGATP writes.
+ *
+ * Note: If a new CSR is added to this fast-path skip block,
+ * make sure that 'csr_dirty' is set to true in any
+ * ioctl (e.g., KVM_SET_ONE_REG) that modifies it.
+ */
+ if (vcpu != __this_cpu_read(kvm_former_vcpu))
+ __this_cpu_write(kvm_former_vcpu, vcpu);
+ else if (vcpu->arch.last_exit_cpu == cpu && !vcpu->arch.csr_dirty)
+ goto csr_restore_done;
+
+ vcpu->arch.csr_dirty = false;
if (kvm_riscv_nacl_sync_csr_available()) {
nsh = nacl_shmem();
nacl_csr_write(nsh, CSR_VSSTATUS, csr->vsstatus);
@@ -624,6 +643,9 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
kvm_riscv_mmu_update_hgatp(vcpu);
+ kvm_riscv_vcpu_aia_load(vcpu, cpu);
+
+csr_restore_done:
kvm_riscv_vcpu_timer_restore(vcpu);
kvm_riscv_vcpu_host_fp_save(&vcpu->arch.host_context);
@@ -633,8 +655,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
kvm_riscv_vcpu_guest_vector_restore(&vcpu->arch.guest_context,
vcpu->arch.isa);
- kvm_riscv_vcpu_aia_load(vcpu, cpu);
-
kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu);
vcpu->cpu = cpu;
diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c
index e7ab6cb00..fc08bf833 100644
--- a/arch/riscv/kvm/vcpu_onereg.c
+++ b/arch/riscv/kvm/vcpu_onereg.c
@@ -652,6 +652,8 @@ static int kvm_riscv_vcpu_set_reg_csr(struct kvm_vcpu *vcpu,
if (rc)
return rc;
+ vcpu->arch.csr_dirty = true;
+
return 0;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v7] KVM: riscv: Skip CSR restore if VCPU is reloaded on the same core
@ 2026-02-27 12:10 ` Jinyu Tang
0 siblings, 0 replies; 15+ messages in thread
From: Jinyu Tang @ 2026-02-27 12:10 UTC (permalink / raw)
To: Radim Krčmář, Anup Patel, Atish Patra,
Andrew Jones, Conor Dooley, Yong-Xuan Wang, Nutty Liu,
Paul Walmsley, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti
Cc: kvm, kvm-riscv, linux-riscv, linux-kernel, Jinyu Tang
Currently, kvm_arch_vcpu_load() unconditionally restores guest CSRs,
HGATP, and AIA state. However, when a VCPU is loaded back on the same
physical CPU, and no other KVM VCPU has run on this CPU since it was
last put, the hardware CSRs and AIA registers are still valid.
This patch optimizes the vcpu_load path by skipping the expensive CSR
and AIA writes if all the following conditions are met:
1. It is being reloaded on the same CPU (vcpu->arch.last_exit_cpu == cpu).
2. The CSRs are not dirty (!vcpu->arch.csr_dirty).
3. No other VCPU used this CPU (vcpu == __this_cpu_read(kvm_former_vcpu)).
To ensure this fast-path doesn't break corner cases:
- Live migration and VCPU reset are naturally safe. KVM initializes
last_exit_cpu to -1, which guarantees the fast-path won't trigger.
- The 'csr_dirty' flag tracks runtime userspace interventions. If
userspace modifies guest configurations (e.g., hedeleg via
KVM_SET_GUEST_DEBUG, or CSRs including AIA via KVM_SET_ONE_REG),
the flag is set to skip the fast path.
With the 'csr_dirty' safeguard proven effective, it is safe to
include kvm_riscv_vcpu_aia_load() inside the skip logic now.
Signed-off-by: Jinyu Tang <tjytimi@163.com>
---
v6 -> v7:
- Moved kvm_riscv_vcpu_aia_load() into the fast-path skip logic, as
suggested by Radim Krčmář.
- Verified the fix for the IMSIC instability issue reported in v3.
Testing was conducted on QEMU 10.0.2 with explicitly enabled AIA
(`-machine virt,aia=aplic-imsic`). The guest boots successfully
using virtio-mmio devices like virtio-blk and virtio-net.
v5 -> v6:
As suggested by Andrew Jones, checking 'last_exit_cpu' first (most
likely to fail on busy hosts) and placing the expensive
__this_cpu_read() last, skipping __this_cpu_write() in kvm_arch_vcpu_put()
if kvm_former_vcpu is already set to the current VCPU.
v4 -> v5:
- Dropped the 'vcpu->scheduled_out' check as Andrew Jones pointed out,
relying on 'last_exit_cpu', 'former_vcpu', and '!csr_dirty'
is sufficient and safe. This expands the optimization to cover many
userspace exits (e.g., MMIO) as well.
- Added a block comment in kvm_arch_vcpu_load() to warn future
developers about maintaining the 'csr_dirty' dependency, as Andrew's
suggestion to reduce fragility.
- Removed unnecessary single-line comments and fixed indentation nits.
v3 -> v4:
- Addressed Anup Patel's review regarding hardware state inconsistency.
- Introduced 'csr_dirty' flag to track dynamic userspace CSR/CONFIG
modifications (KVM_SET_ONE_REG, KVM_SET_GUEST_DEBUG), forcing a full
restore when debugging or modifying states at userspace.
- Kept kvm_riscv_vcpu_aia_load() out of the skip block to resolve IMSIC
VS-file instability.
v2 -> v3:
v2 was missing a critical check because I generated the patch from my
wrong (experimental) branch. This is fixed in v3. Sorry for my trouble.
v1 -> v2:
Apply the logic to aia csr load. Thanks for Andrew Jones's advice.
---
arch/riscv/include/asm/kvm_host.h | 3 +++
arch/riscv/kvm/vcpu.c | 24 ++++++++++++++++++++++--
arch/riscv/kvm/vcpu_onereg.c | 2 ++
3 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h
index 24585304c..7ee47b83c 100644
--- a/arch/riscv/include/asm/kvm_host.h
+++ b/arch/riscv/include/asm/kvm_host.h
@@ -273,6 +273,9 @@ struct kvm_vcpu_arch {
/* 'static' configurations which are set only once */
struct kvm_vcpu_config cfg;
+ /* Indicates modified guest CSRs */
+ bool csr_dirty;
+
/* SBI steal-time accounting */
struct {
gpa_t shmem;
diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c
index a55a95da5..2e4dfff07 100644
--- a/arch/riscv/kvm/vcpu.c
+++ b/arch/riscv/kvm/vcpu.c
@@ -24,6 +24,8 @@
#define CREATE_TRACE_POINTS
#include "trace.h"
+static DEFINE_PER_CPU(struct kvm_vcpu *, kvm_former_vcpu);
+
const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
KVM_GENERIC_VCPU_STATS(),
STATS_DESC_COUNTER(VCPU, ecall_exit_stat),
@@ -537,6 +539,8 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
vcpu->arch.cfg.hedeleg |= BIT(EXC_BREAKPOINT);
}
+ vcpu->arch.csr_dirty = true;
+
return 0;
}
@@ -581,6 +585,21 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
struct kvm_vcpu_config *cfg = &vcpu->arch.cfg;
+ /*
+ * If VCPU is being reloaded on the same physical CPU and no
+ * other KVM VCPU has run on this CPU since it was last put,
+ * we can skip the expensive CSR and HGATP writes.
+ *
+ * Note: If a new CSR is added to this fast-path skip block,
+ * make sure that 'csr_dirty' is set to true in any
+ * ioctl (e.g., KVM_SET_ONE_REG) that modifies it.
+ */
+ if (vcpu != __this_cpu_read(kvm_former_vcpu))
+ __this_cpu_write(kvm_former_vcpu, vcpu);
+ else if (vcpu->arch.last_exit_cpu == cpu && !vcpu->arch.csr_dirty)
+ goto csr_restore_done;
+
+ vcpu->arch.csr_dirty = false;
if (kvm_riscv_nacl_sync_csr_available()) {
nsh = nacl_shmem();
nacl_csr_write(nsh, CSR_VSSTATUS, csr->vsstatus);
@@ -624,6 +643,9 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
kvm_riscv_mmu_update_hgatp(vcpu);
+ kvm_riscv_vcpu_aia_load(vcpu, cpu);
+
+csr_restore_done:
kvm_riscv_vcpu_timer_restore(vcpu);
kvm_riscv_vcpu_host_fp_save(&vcpu->arch.host_context);
@@ -633,8 +655,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
kvm_riscv_vcpu_guest_vector_restore(&vcpu->arch.guest_context,
vcpu->arch.isa);
- kvm_riscv_vcpu_aia_load(vcpu, cpu);
-
kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu);
vcpu->cpu = cpu;
diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c
index e7ab6cb00..fc08bf833 100644
--- a/arch/riscv/kvm/vcpu_onereg.c
+++ b/arch/riscv/kvm/vcpu_onereg.c
@@ -652,6 +652,8 @@ static int kvm_riscv_vcpu_set_reg_csr(struct kvm_vcpu *vcpu,
if (rc)
return rc;
+ vcpu->arch.csr_dirty = true;
+
return 0;
}
--
2.43.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v7] KVM: riscv: Skip CSR restore if VCPU is reloaded on the same core
2026-02-27 12:10 ` Jinyu Tang
(?)
@ 2026-02-27 14:00 ` Radim Krčmář
-1 siblings, 0 replies; 15+ messages in thread
From: Radim Krčmář @ 2026-02-27 14:00 UTC (permalink / raw)
To: Jinyu Tang, Anup Patel, Atish Patra, Andrew Jones, Conor Dooley,
Yong-Xuan Wang, Nutty Liu, Paul Walmsley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: kvm, kvm-riscv, linux-riscv, linux-kernel
2026-02-27T20:10:08+08:00, Jinyu Tang <tjytimi@163.com>:
> Currently, kvm_arch_vcpu_load() unconditionally restores guest CSRs,
> HGATP, and AIA state. However, when a VCPU is loaded back on the same
> physical CPU, and no other KVM VCPU has run on this CPU since it was
> last put, the hardware CSRs and AIA registers are still valid.
>
> This patch optimizes the vcpu_load path by skipping the expensive CSR
> and AIA writes if all the following conditions are met:
> 1. It is being reloaded on the same CPU (vcpu->arch.last_exit_cpu == cpu).
> 2. The CSRs are not dirty (!vcpu->arch.csr_dirty).
> 3. No other VCPU used this CPU (vcpu == __this_cpu_read(kvm_former_vcpu)).
>
> To ensure this fast-path doesn't break corner cases:
> - Live migration and VCPU reset are naturally safe. KVM initializes
> last_exit_cpu to -1, which guarantees the fast-path won't trigger.
> - The 'csr_dirty' flag tracks runtime userspace interventions. If
> userspace modifies guest configurations (e.g., hedeleg via
> KVM_SET_GUEST_DEBUG, or CSRs including AIA via KVM_SET_ONE_REG),
> the flag is set to skip the fast path.
>
> With the 'csr_dirty' safeguard proven effective, it is safe to
> include kvm_riscv_vcpu_aia_load() inside the skip logic now.
>
> Signed-off-by: Jinyu Tang <tjytimi@163.com>
> ---
> v6 -> v7:
> - Moved kvm_riscv_vcpu_aia_load() into the fast-path skip logic, as
> suggested by Radim Krčmář.
> - Verified the fix for the IMSIC instability issue reported in v3.
> Testing was conducted on QEMU 10.0.2 with explicitly enabled AIA
> (`-machine virt,aia=aplic-imsic`). The guest boots successfully
> using virtio-mmio devices like virtio-blk and virtio-net.
Reviewed-by: Radim Krčmář <radim.krcmar@oss.qualcomm.com>
Thanks.
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v7] KVM: riscv: Skip CSR restore if VCPU is reloaded on the same core
@ 2026-02-27 14:00 ` Radim Krčmář
0 siblings, 0 replies; 15+ messages in thread
From: Radim Krčmář @ 2026-02-27 14:00 UTC (permalink / raw)
To: Jinyu Tang, Anup Patel, Atish Patra, Andrew Jones, Conor Dooley,
Yong-Xuan Wang, Nutty Liu, Paul Walmsley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: kvm, kvm-riscv, linux-riscv, linux-kernel
2026-02-27T20:10:08+08:00, Jinyu Tang <tjytimi@163.com>:
> Currently, kvm_arch_vcpu_load() unconditionally restores guest CSRs,
> HGATP, and AIA state. However, when a VCPU is loaded back on the same
> physical CPU, and no other KVM VCPU has run on this CPU since it was
> last put, the hardware CSRs and AIA registers are still valid.
>
> This patch optimizes the vcpu_load path by skipping the expensive CSR
> and AIA writes if all the following conditions are met:
> 1. It is being reloaded on the same CPU (vcpu->arch.last_exit_cpu == cpu).
> 2. The CSRs are not dirty (!vcpu->arch.csr_dirty).
> 3. No other VCPU used this CPU (vcpu == __this_cpu_read(kvm_former_vcpu)).
>
> To ensure this fast-path doesn't break corner cases:
> - Live migration and VCPU reset are naturally safe. KVM initializes
> last_exit_cpu to -1, which guarantees the fast-path won't trigger.
> - The 'csr_dirty' flag tracks runtime userspace interventions. If
> userspace modifies guest configurations (e.g., hedeleg via
> KVM_SET_GUEST_DEBUG, or CSRs including AIA via KVM_SET_ONE_REG),
> the flag is set to skip the fast path.
>
> With the 'csr_dirty' safeguard proven effective, it is safe to
> include kvm_riscv_vcpu_aia_load() inside the skip logic now.
>
> Signed-off-by: Jinyu Tang <tjytimi@163.com>
> ---
> v6 -> v7:
> - Moved kvm_riscv_vcpu_aia_load() into the fast-path skip logic, as
> suggested by Radim Krčmář.
> - Verified the fix for the IMSIC instability issue reported in v3.
> Testing was conducted on QEMU 10.0.2 with explicitly enabled AIA
> (`-machine virt,aia=aplic-imsic`). The guest boots successfully
> using virtio-mmio devices like virtio-blk and virtio-net.
Reviewed-by: Radim Krčmář <radim.krcmar@oss.qualcomm.com>
Thanks.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v7] KVM: riscv: Skip CSR restore if VCPU is reloaded on the same core
@ 2026-02-27 14:00 ` Radim Krčmář
0 siblings, 0 replies; 15+ messages in thread
From: Radim Krčmář @ 2026-02-27 14:00 UTC (permalink / raw)
To: Jinyu Tang, Anup Patel, Atish Patra, Andrew Jones, Conor Dooley,
Yong-Xuan Wang, Nutty Liu, Paul Walmsley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: kvm, kvm-riscv, linux-riscv, linux-kernel
2026-02-27T20:10:08+08:00, Jinyu Tang <tjytimi@163.com>:
> Currently, kvm_arch_vcpu_load() unconditionally restores guest CSRs,
> HGATP, and AIA state. However, when a VCPU is loaded back on the same
> physical CPU, and no other KVM VCPU has run on this CPU since it was
> last put, the hardware CSRs and AIA registers are still valid.
>
> This patch optimizes the vcpu_load path by skipping the expensive CSR
> and AIA writes if all the following conditions are met:
> 1. It is being reloaded on the same CPU (vcpu->arch.last_exit_cpu == cpu).
> 2. The CSRs are not dirty (!vcpu->arch.csr_dirty).
> 3. No other VCPU used this CPU (vcpu == __this_cpu_read(kvm_former_vcpu)).
>
> To ensure this fast-path doesn't break corner cases:
> - Live migration and VCPU reset are naturally safe. KVM initializes
> last_exit_cpu to -1, which guarantees the fast-path won't trigger.
> - The 'csr_dirty' flag tracks runtime userspace interventions. If
> userspace modifies guest configurations (e.g., hedeleg via
> KVM_SET_GUEST_DEBUG, or CSRs including AIA via KVM_SET_ONE_REG),
> the flag is set to skip the fast path.
>
> With the 'csr_dirty' safeguard proven effective, it is safe to
> include kvm_riscv_vcpu_aia_load() inside the skip logic now.
>
> Signed-off-by: Jinyu Tang <tjytimi@163.com>
> ---
> v6 -> v7:
> - Moved kvm_riscv_vcpu_aia_load() into the fast-path skip logic, as
> suggested by Radim Krčmář.
> - Verified the fix for the IMSIC instability issue reported in v3.
> Testing was conducted on QEMU 10.0.2 with explicitly enabled AIA
> (`-machine virt,aia=aplic-imsic`). The guest boots successfully
> using virtio-mmio devices like virtio-blk and virtio-net.
Reviewed-by: Radim Krčmář <radim.krcmar@oss.qualcomm.com>
Thanks.
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v7] KVM: riscv: Skip CSR restore if VCPU is reloaded on the same core
2026-02-27 12:10 ` Jinyu Tang
(?)
@ 2026-03-02 22:18 ` Andrew Jones
-1 siblings, 0 replies; 15+ messages in thread
From: Andrew Jones @ 2026-03-02 22:18 UTC (permalink / raw)
To: Jinyu Tang
Cc: Radim Krčmář, Anup Patel, Atish Patra,
Conor Dooley, Yong-Xuan Wang, Nutty Liu, Paul Walmsley,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, kvm,
kvm-riscv, linux-riscv, linux-kernel
On Fri, Feb 27, 2026 at 08:10:08PM +0800, Jinyu Tang wrote:
> Currently, kvm_arch_vcpu_load() unconditionally restores guest CSRs,
> HGATP, and AIA state. However, when a VCPU is loaded back on the same
> physical CPU, and no other KVM VCPU has run on this CPU since it was
> last put, the hardware CSRs and AIA registers are still valid.
>
> This patch optimizes the vcpu_load path by skipping the expensive CSR
> and AIA writes if all the following conditions are met:
> 1. It is being reloaded on the same CPU (vcpu->arch.last_exit_cpu == cpu).
> 2. The CSRs are not dirty (!vcpu->arch.csr_dirty).
> 3. No other VCPU used this CPU (vcpu == __this_cpu_read(kvm_former_vcpu)).
>
> To ensure this fast-path doesn't break corner cases:
> - Live migration and VCPU reset are naturally safe. KVM initializes
> last_exit_cpu to -1, which guarantees the fast-path won't trigger.
> - The 'csr_dirty' flag tracks runtime userspace interventions. If
> userspace modifies guest configurations (e.g., hedeleg via
> KVM_SET_GUEST_DEBUG, or CSRs including AIA via KVM_SET_ONE_REG),
> the flag is set to skip the fast path.
>
> With the 'csr_dirty' safeguard proven effective, it is safe to
> include kvm_riscv_vcpu_aia_load() inside the skip logic now.
>
> Signed-off-by: Jinyu Tang <tjytimi@163.com>
> ---
> v6 -> v7:
> - Moved kvm_riscv_vcpu_aia_load() into the fast-path skip logic, as
> suggested by Radim Krčmář.
> - Verified the fix for the IMSIC instability issue reported in v3.
> Testing was conducted on QEMU 10.0.2 with explicitly enabled AIA
> (`-machine virt,aia=aplic-imsic`). The guest boots successfully
> using virtio-mmio devices like virtio-blk and virtio-net.
>
> v5 -> v6:
> As suggested by Andrew Jones, checking 'last_exit_cpu' first (most
> likely to fail on busy hosts) and placing the expensive
> __this_cpu_read() last, skipping __this_cpu_write() in kvm_arch_vcpu_put()
> if kvm_former_vcpu is already set to the current VCPU.
>
> v4 -> v5:
> - Dropped the 'vcpu->scheduled_out' check as Andrew Jones pointed out,
> relying on 'last_exit_cpu', 'former_vcpu', and '!csr_dirty'
> is sufficient and safe. This expands the optimization to cover many
> userspace exits (e.g., MMIO) as well.
> - Added a block comment in kvm_arch_vcpu_load() to warn future
> developers about maintaining the 'csr_dirty' dependency, as Andrew's
> suggestion to reduce fragility.
> - Removed unnecessary single-line comments and fixed indentation nits.
>
> v3 -> v4:
> - Addressed Anup Patel's review regarding hardware state inconsistency.
> - Introduced 'csr_dirty' flag to track dynamic userspace CSR/CONFIG
> modifications (KVM_SET_ONE_REG, KVM_SET_GUEST_DEBUG), forcing a full
> restore when debugging or modifying states at userspace.
> - Kept kvm_riscv_vcpu_aia_load() out of the skip block to resolve IMSIC
> VS-file instability.
>
> v2 -> v3:
> v2 was missing a critical check because I generated the patch from my
> wrong (experimental) branch. This is fixed in v3. Sorry for my trouble.
>
> v1 -> v2:
> Apply the logic to aia csr load. Thanks for Andrew Jones's advice.
> ---
> arch/riscv/include/asm/kvm_host.h | 3 +++
> arch/riscv/kvm/vcpu.c | 24 ++++++++++++++++++++++--
> arch/riscv/kvm/vcpu_onereg.c | 2 ++
> 3 files changed, 27 insertions(+), 2 deletions(-)
>
Reviewed-by: Andrew Jones <andrew.jones@oss.qualcomm.com>
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v7] KVM: riscv: Skip CSR restore if VCPU is reloaded on the same core
@ 2026-03-02 22:18 ` Andrew Jones
0 siblings, 0 replies; 15+ messages in thread
From: Andrew Jones @ 2026-03-02 22:18 UTC (permalink / raw)
To: Jinyu Tang
Cc: Radim Krčmář, Anup Patel, Atish Patra,
Conor Dooley, Yong-Xuan Wang, Nutty Liu, Paul Walmsley,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, kvm,
kvm-riscv, linux-riscv, linux-kernel
On Fri, Feb 27, 2026 at 08:10:08PM +0800, Jinyu Tang wrote:
> Currently, kvm_arch_vcpu_load() unconditionally restores guest CSRs,
> HGATP, and AIA state. However, when a VCPU is loaded back on the same
> physical CPU, and no other KVM VCPU has run on this CPU since it was
> last put, the hardware CSRs and AIA registers are still valid.
>
> This patch optimizes the vcpu_load path by skipping the expensive CSR
> and AIA writes if all the following conditions are met:
> 1. It is being reloaded on the same CPU (vcpu->arch.last_exit_cpu == cpu).
> 2. The CSRs are not dirty (!vcpu->arch.csr_dirty).
> 3. No other VCPU used this CPU (vcpu == __this_cpu_read(kvm_former_vcpu)).
>
> To ensure this fast-path doesn't break corner cases:
> - Live migration and VCPU reset are naturally safe. KVM initializes
> last_exit_cpu to -1, which guarantees the fast-path won't trigger.
> - The 'csr_dirty' flag tracks runtime userspace interventions. If
> userspace modifies guest configurations (e.g., hedeleg via
> KVM_SET_GUEST_DEBUG, or CSRs including AIA via KVM_SET_ONE_REG),
> the flag is set to skip the fast path.
>
> With the 'csr_dirty' safeguard proven effective, it is safe to
> include kvm_riscv_vcpu_aia_load() inside the skip logic now.
>
> Signed-off-by: Jinyu Tang <tjytimi@163.com>
> ---
> v6 -> v7:
> - Moved kvm_riscv_vcpu_aia_load() into the fast-path skip logic, as
> suggested by Radim Krčmář.
> - Verified the fix for the IMSIC instability issue reported in v3.
> Testing was conducted on QEMU 10.0.2 with explicitly enabled AIA
> (`-machine virt,aia=aplic-imsic`). The guest boots successfully
> using virtio-mmio devices like virtio-blk and virtio-net.
>
> v5 -> v6:
> As suggested by Andrew Jones, checking 'last_exit_cpu' first (most
> likely to fail on busy hosts) and placing the expensive
> __this_cpu_read() last, skipping __this_cpu_write() in kvm_arch_vcpu_put()
> if kvm_former_vcpu is already set to the current VCPU.
>
> v4 -> v5:
> - Dropped the 'vcpu->scheduled_out' check as Andrew Jones pointed out,
> relying on 'last_exit_cpu', 'former_vcpu', and '!csr_dirty'
> is sufficient and safe. This expands the optimization to cover many
> userspace exits (e.g., MMIO) as well.
> - Added a block comment in kvm_arch_vcpu_load() to warn future
> developers about maintaining the 'csr_dirty' dependency, as Andrew's
> suggestion to reduce fragility.
> - Removed unnecessary single-line comments and fixed indentation nits.
>
> v3 -> v4:
> - Addressed Anup Patel's review regarding hardware state inconsistency.
> - Introduced 'csr_dirty' flag to track dynamic userspace CSR/CONFIG
> modifications (KVM_SET_ONE_REG, KVM_SET_GUEST_DEBUG), forcing a full
> restore when debugging or modifying states at userspace.
> - Kept kvm_riscv_vcpu_aia_load() out of the skip block to resolve IMSIC
> VS-file instability.
>
> v2 -> v3:
> v2 was missing a critical check because I generated the patch from my
> wrong (experimental) branch. This is fixed in v3. Sorry for my trouble.
>
> v1 -> v2:
> Apply the logic to aia csr load. Thanks for Andrew Jones's advice.
> ---
> arch/riscv/include/asm/kvm_host.h | 3 +++
> arch/riscv/kvm/vcpu.c | 24 ++++++++++++++++++++++--
> arch/riscv/kvm/vcpu_onereg.c | 2 ++
> 3 files changed, 27 insertions(+), 2 deletions(-)
>
Reviewed-by: Andrew Jones <andrew.jones@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v7] KVM: riscv: Skip CSR restore if VCPU is reloaded on the same core
@ 2026-03-02 22:18 ` Andrew Jones
0 siblings, 0 replies; 15+ messages in thread
From: Andrew Jones @ 2026-03-02 22:18 UTC (permalink / raw)
To: Jinyu Tang
Cc: Radim Krčmář, Anup Patel, Atish Patra,
Conor Dooley, Yong-Xuan Wang, Nutty Liu, Paul Walmsley,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, kvm,
kvm-riscv, linux-riscv, linux-kernel
On Fri, Feb 27, 2026 at 08:10:08PM +0800, Jinyu Tang wrote:
> Currently, kvm_arch_vcpu_load() unconditionally restores guest CSRs,
> HGATP, and AIA state. However, when a VCPU is loaded back on the same
> physical CPU, and no other KVM VCPU has run on this CPU since it was
> last put, the hardware CSRs and AIA registers are still valid.
>
> This patch optimizes the vcpu_load path by skipping the expensive CSR
> and AIA writes if all the following conditions are met:
> 1. It is being reloaded on the same CPU (vcpu->arch.last_exit_cpu == cpu).
> 2. The CSRs are not dirty (!vcpu->arch.csr_dirty).
> 3. No other VCPU used this CPU (vcpu == __this_cpu_read(kvm_former_vcpu)).
>
> To ensure this fast-path doesn't break corner cases:
> - Live migration and VCPU reset are naturally safe. KVM initializes
> last_exit_cpu to -1, which guarantees the fast-path won't trigger.
> - The 'csr_dirty' flag tracks runtime userspace interventions. If
> userspace modifies guest configurations (e.g., hedeleg via
> KVM_SET_GUEST_DEBUG, or CSRs including AIA via KVM_SET_ONE_REG),
> the flag is set to skip the fast path.
>
> With the 'csr_dirty' safeguard proven effective, it is safe to
> include kvm_riscv_vcpu_aia_load() inside the skip logic now.
>
> Signed-off-by: Jinyu Tang <tjytimi@163.com>
> ---
> v6 -> v7:
> - Moved kvm_riscv_vcpu_aia_load() into the fast-path skip logic, as
> suggested by Radim Krčmář.
> - Verified the fix for the IMSIC instability issue reported in v3.
> Testing was conducted on QEMU 10.0.2 with explicitly enabled AIA
> (`-machine virt,aia=aplic-imsic`). The guest boots successfully
> using virtio-mmio devices like virtio-blk and virtio-net.
>
> v5 -> v6:
> As suggested by Andrew Jones, checking 'last_exit_cpu' first (most
> likely to fail on busy hosts) and placing the expensive
> __this_cpu_read() last, skipping __this_cpu_write() in kvm_arch_vcpu_put()
> if kvm_former_vcpu is already set to the current VCPU.
>
> v4 -> v5:
> - Dropped the 'vcpu->scheduled_out' check as Andrew Jones pointed out,
> relying on 'last_exit_cpu', 'former_vcpu', and '!csr_dirty'
> is sufficient and safe. This expands the optimization to cover many
> userspace exits (e.g., MMIO) as well.
> - Added a block comment in kvm_arch_vcpu_load() to warn future
> developers about maintaining the 'csr_dirty' dependency, as Andrew's
> suggestion to reduce fragility.
> - Removed unnecessary single-line comments and fixed indentation nits.
>
> v3 -> v4:
> - Addressed Anup Patel's review regarding hardware state inconsistency.
> - Introduced 'csr_dirty' flag to track dynamic userspace CSR/CONFIG
> modifications (KVM_SET_ONE_REG, KVM_SET_GUEST_DEBUG), forcing a full
> restore when debugging or modifying states at userspace.
> - Kept kvm_riscv_vcpu_aia_load() out of the skip block to resolve IMSIC
> VS-file instability.
>
> v2 -> v3:
> v2 was missing a critical check because I generated the patch from my
> wrong (experimental) branch. This is fixed in v3. Sorry for my trouble.
>
> v1 -> v2:
> Apply the logic to aia csr load. Thanks for Andrew Jones's advice.
> ---
> arch/riscv/include/asm/kvm_host.h | 3 +++
> arch/riscv/kvm/vcpu.c | 24 ++++++++++++++++++++++--
> arch/riscv/kvm/vcpu_onereg.c | 2 ++
> 3 files changed, 27 insertions(+), 2 deletions(-)
>
Reviewed-by: Andrew Jones <andrew.jones@oss.qualcomm.com>
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v7] KVM: riscv: Skip CSR restore if VCPU is reloaded on the same core
2026-02-27 12:10 ` Jinyu Tang
(?)
@ 2026-03-03 3:13 ` Nutty.Liu
-1 siblings, 0 replies; 15+ messages in thread
From: Nutty.Liu @ 2026-03-03 3:13 UTC (permalink / raw)
To: Jinyu Tang, Radim Krčmář, Anup Patel, Atish Patra,
Andrew Jones, Conor Dooley, Yong-Xuan Wang, Paul Walmsley,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: kvm, kvm-riscv, linux-riscv, linux-kernel
On 2/27/2026 8:10 PM, Jinyu Tang wrote:
> Currently, kvm_arch_vcpu_load() unconditionally restores guest CSRs,
> HGATP, and AIA state. However, when a VCPU is loaded back on the same
> physical CPU, and no other KVM VCPU has run on this CPU since it was
> last put, the hardware CSRs and AIA registers are still valid.
>
> This patch optimizes the vcpu_load path by skipping the expensive CSR
> and AIA writes if all the following conditions are met:
> 1. It is being reloaded on the same CPU (vcpu->arch.last_exit_cpu == cpu).
> 2. The CSRs are not dirty (!vcpu->arch.csr_dirty).
> 3. No other VCPU used this CPU (vcpu == __this_cpu_read(kvm_former_vcpu)).
>
> To ensure this fast-path doesn't break corner cases:
> - Live migration and VCPU reset are naturally safe. KVM initializes
> last_exit_cpu to -1, which guarantees the fast-path won't trigger.
> - The 'csr_dirty' flag tracks runtime userspace interventions. If
> userspace modifies guest configurations (e.g., hedeleg via
> KVM_SET_GUEST_DEBUG, or CSRs including AIA via KVM_SET_ONE_REG),
> the flag is set to skip the fast path.
>
> With the 'csr_dirty' safeguard proven effective, it is safe to
> include kvm_riscv_vcpu_aia_load() inside the skip logic now.
>
> Signed-off-by: Jinyu Tang <tjytimi@163.com>
> ---
> v6 -> v7:
> - Moved kvm_riscv_vcpu_aia_load() into the fast-path skip logic, as
> suggested by Radim Krčmář.
> - Verified the fix for the IMSIC instability issue reported in v3.
> Testing was conducted on QEMU 10.0.2 with explicitly enabled AIA
> (`-machine virt,aia=aplic-imsic`). The guest boots successfully
> using virtio-mmio devices like virtio-blk and virtio-net.
>
> v5 -> v6:
> As suggested by Andrew Jones, checking 'last_exit_cpu' first (most
> likely to fail on busy hosts) and placing the expensive
> __this_cpu_read() last, skipping __this_cpu_write() in kvm_arch_vcpu_put()
> if kvm_former_vcpu is already set to the current VCPU.
>
> v4 -> v5:
> - Dropped the 'vcpu->scheduled_out' check as Andrew Jones pointed out,
> relying on 'last_exit_cpu', 'former_vcpu', and '!csr_dirty'
> is sufficient and safe. This expands the optimization to cover many
> userspace exits (e.g., MMIO) as well.
> - Added a block comment in kvm_arch_vcpu_load() to warn future
> developers about maintaining the 'csr_dirty' dependency, as Andrew's
> suggestion to reduce fragility.
> - Removed unnecessary single-line comments and fixed indentation nits.
>
> v3 -> v4:
> - Addressed Anup Patel's review regarding hardware state inconsistency.
> - Introduced 'csr_dirty' flag to track dynamic userspace CSR/CONFIG
> modifications (KVM_SET_ONE_REG, KVM_SET_GUEST_DEBUG), forcing a full
> restore when debugging or modifying states at userspace.
> - Kept kvm_riscv_vcpu_aia_load() out of the skip block to resolve IMSIC
> VS-file instability.
>
> v2 -> v3:
> v2 was missing a critical check because I generated the patch from my
> wrong (experimental) branch. This is fixed in v3. Sorry for my trouble.
>
> v1 -> v2:
> Apply the logic to aia csr load. Thanks for Andrew Jones's advice.
> ---
> arch/riscv/include/asm/kvm_host.h | 3 +++
> arch/riscv/kvm/vcpu.c | 24 ++++++++++++++++++++++--
> arch/riscv/kvm/vcpu_onereg.c | 2 ++
> 3 files changed, 27 insertions(+), 2 deletions(-)
Reviewed-by: Nutty Liu <nutty.liu@hotmail.com>
Thanks,
Nutty
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v7] KVM: riscv: Skip CSR restore if VCPU is reloaded on the same core
@ 2026-03-03 3:13 ` Nutty.Liu
0 siblings, 0 replies; 15+ messages in thread
From: Nutty.Liu @ 2026-03-03 3:13 UTC (permalink / raw)
To: Jinyu Tang, Radim Krčmář, Anup Patel, Atish Patra,
Andrew Jones, Conor Dooley, Yong-Xuan Wang, Paul Walmsley,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: kvm, kvm-riscv, linux-riscv, linux-kernel
On 2/27/2026 8:10 PM, Jinyu Tang wrote:
> Currently, kvm_arch_vcpu_load() unconditionally restores guest CSRs,
> HGATP, and AIA state. However, when a VCPU is loaded back on the same
> physical CPU, and no other KVM VCPU has run on this CPU since it was
> last put, the hardware CSRs and AIA registers are still valid.
>
> This patch optimizes the vcpu_load path by skipping the expensive CSR
> and AIA writes if all the following conditions are met:
> 1. It is being reloaded on the same CPU (vcpu->arch.last_exit_cpu == cpu).
> 2. The CSRs are not dirty (!vcpu->arch.csr_dirty).
> 3. No other VCPU used this CPU (vcpu == __this_cpu_read(kvm_former_vcpu)).
>
> To ensure this fast-path doesn't break corner cases:
> - Live migration and VCPU reset are naturally safe. KVM initializes
> last_exit_cpu to -1, which guarantees the fast-path won't trigger.
> - The 'csr_dirty' flag tracks runtime userspace interventions. If
> userspace modifies guest configurations (e.g., hedeleg via
> KVM_SET_GUEST_DEBUG, or CSRs including AIA via KVM_SET_ONE_REG),
> the flag is set to skip the fast path.
>
> With the 'csr_dirty' safeguard proven effective, it is safe to
> include kvm_riscv_vcpu_aia_load() inside the skip logic now.
>
> Signed-off-by: Jinyu Tang <tjytimi@163.com>
> ---
> v6 -> v7:
> - Moved kvm_riscv_vcpu_aia_load() into the fast-path skip logic, as
> suggested by Radim Krčmář.
> - Verified the fix for the IMSIC instability issue reported in v3.
> Testing was conducted on QEMU 10.0.2 with explicitly enabled AIA
> (`-machine virt,aia=aplic-imsic`). The guest boots successfully
> using virtio-mmio devices like virtio-blk and virtio-net.
>
> v5 -> v6:
> As suggested by Andrew Jones, checking 'last_exit_cpu' first (most
> likely to fail on busy hosts) and placing the expensive
> __this_cpu_read() last, skipping __this_cpu_write() in kvm_arch_vcpu_put()
> if kvm_former_vcpu is already set to the current VCPU.
>
> v4 -> v5:
> - Dropped the 'vcpu->scheduled_out' check as Andrew Jones pointed out,
> relying on 'last_exit_cpu', 'former_vcpu', and '!csr_dirty'
> is sufficient and safe. This expands the optimization to cover many
> userspace exits (e.g., MMIO) as well.
> - Added a block comment in kvm_arch_vcpu_load() to warn future
> developers about maintaining the 'csr_dirty' dependency, as Andrew's
> suggestion to reduce fragility.
> - Removed unnecessary single-line comments and fixed indentation nits.
>
> v3 -> v4:
> - Addressed Anup Patel's review regarding hardware state inconsistency.
> - Introduced 'csr_dirty' flag to track dynamic userspace CSR/CONFIG
> modifications (KVM_SET_ONE_REG, KVM_SET_GUEST_DEBUG), forcing a full
> restore when debugging or modifying states at userspace.
> - Kept kvm_riscv_vcpu_aia_load() out of the skip block to resolve IMSIC
> VS-file instability.
>
> v2 -> v3:
> v2 was missing a critical check because I generated the patch from my
> wrong (experimental) branch. This is fixed in v3. Sorry for my trouble.
>
> v1 -> v2:
> Apply the logic to aia csr load. Thanks for Andrew Jones's advice.
> ---
> arch/riscv/include/asm/kvm_host.h | 3 +++
> arch/riscv/kvm/vcpu.c | 24 ++++++++++++++++++++++--
> arch/riscv/kvm/vcpu_onereg.c | 2 ++
> 3 files changed, 27 insertions(+), 2 deletions(-)
Reviewed-by: Nutty Liu <nutty.liu@hotmail.com>
Thanks,
Nutty
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v7] KVM: riscv: Skip CSR restore if VCPU is reloaded on the same core
@ 2026-03-03 3:13 ` Nutty.Liu
0 siblings, 0 replies; 15+ messages in thread
From: Nutty.Liu @ 2026-03-03 3:13 UTC (permalink / raw)
To: Jinyu Tang, Radim Krčmář, Anup Patel, Atish Patra,
Andrew Jones, Conor Dooley, Yong-Xuan Wang, Paul Walmsley,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: kvm, kvm-riscv, linux-riscv, linux-kernel
On 2/27/2026 8:10 PM, Jinyu Tang wrote:
> Currently, kvm_arch_vcpu_load() unconditionally restores guest CSRs,
> HGATP, and AIA state. However, when a VCPU is loaded back on the same
> physical CPU, and no other KVM VCPU has run on this CPU since it was
> last put, the hardware CSRs and AIA registers are still valid.
>
> This patch optimizes the vcpu_load path by skipping the expensive CSR
> and AIA writes if all the following conditions are met:
> 1. It is being reloaded on the same CPU (vcpu->arch.last_exit_cpu == cpu).
> 2. The CSRs are not dirty (!vcpu->arch.csr_dirty).
> 3. No other VCPU used this CPU (vcpu == __this_cpu_read(kvm_former_vcpu)).
>
> To ensure this fast-path doesn't break corner cases:
> - Live migration and VCPU reset are naturally safe. KVM initializes
> last_exit_cpu to -1, which guarantees the fast-path won't trigger.
> - The 'csr_dirty' flag tracks runtime userspace interventions. If
> userspace modifies guest configurations (e.g., hedeleg via
> KVM_SET_GUEST_DEBUG, or CSRs including AIA via KVM_SET_ONE_REG),
> the flag is set to skip the fast path.
>
> With the 'csr_dirty' safeguard proven effective, it is safe to
> include kvm_riscv_vcpu_aia_load() inside the skip logic now.
>
> Signed-off-by: Jinyu Tang <tjytimi@163.com>
> ---
> v6 -> v7:
> - Moved kvm_riscv_vcpu_aia_load() into the fast-path skip logic, as
> suggested by Radim Krčmář.
> - Verified the fix for the IMSIC instability issue reported in v3.
> Testing was conducted on QEMU 10.0.2 with explicitly enabled AIA
> (`-machine virt,aia=aplic-imsic`). The guest boots successfully
> using virtio-mmio devices like virtio-blk and virtio-net.
>
> v5 -> v6:
> As suggested by Andrew Jones, checking 'last_exit_cpu' first (most
> likely to fail on busy hosts) and placing the expensive
> __this_cpu_read() last, skipping __this_cpu_write() in kvm_arch_vcpu_put()
> if kvm_former_vcpu is already set to the current VCPU.
>
> v4 -> v5:
> - Dropped the 'vcpu->scheduled_out' check as Andrew Jones pointed out,
> relying on 'last_exit_cpu', 'former_vcpu', and '!csr_dirty'
> is sufficient and safe. This expands the optimization to cover many
> userspace exits (e.g., MMIO) as well.
> - Added a block comment in kvm_arch_vcpu_load() to warn future
> developers about maintaining the 'csr_dirty' dependency, as Andrew's
> suggestion to reduce fragility.
> - Removed unnecessary single-line comments and fixed indentation nits.
>
> v3 -> v4:
> - Addressed Anup Patel's review regarding hardware state inconsistency.
> - Introduced 'csr_dirty' flag to track dynamic userspace CSR/CONFIG
> modifications (KVM_SET_ONE_REG, KVM_SET_GUEST_DEBUG), forcing a full
> restore when debugging or modifying states at userspace.
> - Kept kvm_riscv_vcpu_aia_load() out of the skip block to resolve IMSIC
> VS-file instability.
>
> v2 -> v3:
> v2 was missing a critical check because I generated the patch from my
> wrong (experimental) branch. This is fixed in v3. Sorry for my trouble.
>
> v1 -> v2:
> Apply the logic to aia csr load. Thanks for Andrew Jones's advice.
> ---
> arch/riscv/include/asm/kvm_host.h | 3 +++
> arch/riscv/kvm/vcpu.c | 24 ++++++++++++++++++++++--
> arch/riscv/kvm/vcpu_onereg.c | 2 ++
> 3 files changed, 27 insertions(+), 2 deletions(-)
Reviewed-by: Nutty Liu <nutty.liu@hotmail.com>
Thanks,
Nutty
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v7] KVM: riscv: Skip CSR restore if VCPU is reloaded on the same core
2026-02-27 12:10 ` Jinyu Tang
(?)
@ 2026-04-02 13:28 ` Anup Patel
-1 siblings, 0 replies; 15+ messages in thread
From: Anup Patel @ 2026-04-02 13:28 UTC (permalink / raw)
To: Jinyu Tang
Cc: Radim Krčmář, Atish Patra, Andrew Jones,
Conor Dooley, Yong-Xuan Wang, Nutty Liu, Paul Walmsley,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, kvm,
kvm-riscv, linux-riscv, linux-kernel
On Fri, Feb 27, 2026 at 5:40 PM Jinyu Tang <tjytimi@163.com> wrote:
>
> Currently, kvm_arch_vcpu_load() unconditionally restores guest CSRs,
> HGATP, and AIA state. However, when a VCPU is loaded back on the same
> physical CPU, and no other KVM VCPU has run on this CPU since it was
> last put, the hardware CSRs and AIA registers are still valid.
>
> This patch optimizes the vcpu_load path by skipping the expensive CSR
> and AIA writes if all the following conditions are met:
> 1. It is being reloaded on the same CPU (vcpu->arch.last_exit_cpu == cpu).
> 2. The CSRs are not dirty (!vcpu->arch.csr_dirty).
> 3. No other VCPU used this CPU (vcpu == __this_cpu_read(kvm_former_vcpu)).
>
> To ensure this fast-path doesn't break corner cases:
> - Live migration and VCPU reset are naturally safe. KVM initializes
> last_exit_cpu to -1, which guarantees the fast-path won't trigger.
> - The 'csr_dirty' flag tracks runtime userspace interventions. If
> userspace modifies guest configurations (e.g., hedeleg via
> KVM_SET_GUEST_DEBUG, or CSRs including AIA via KVM_SET_ONE_REG),
> the flag is set to skip the fast path.
>
> With the 'csr_dirty' safeguard proven effective, it is safe to
> include kvm_riscv_vcpu_aia_load() inside the skip logic now.
>
> Signed-off-by: Jinyu Tang <tjytimi@163.com>
Queued this patch for Linux-7.1
Thanks,
Anup
> ---
> v6 -> v7:
> - Moved kvm_riscv_vcpu_aia_load() into the fast-path skip logic, as
> suggested by Radim Krčmář.
> - Verified the fix for the IMSIC instability issue reported in v3.
> Testing was conducted on QEMU 10.0.2 with explicitly enabled AIA
> (`-machine virt,aia=aplic-imsic`). The guest boots successfully
> using virtio-mmio devices like virtio-blk and virtio-net.
>
> v5 -> v6:
> As suggested by Andrew Jones, checking 'last_exit_cpu' first (most
> likely to fail on busy hosts) and placing the expensive
> __this_cpu_read() last, skipping __this_cpu_write() in kvm_arch_vcpu_put()
> if kvm_former_vcpu is already set to the current VCPU.
>
> v4 -> v5:
> - Dropped the 'vcpu->scheduled_out' check as Andrew Jones pointed out,
> relying on 'last_exit_cpu', 'former_vcpu', and '!csr_dirty'
> is sufficient and safe. This expands the optimization to cover many
> userspace exits (e.g., MMIO) as well.
> - Added a block comment in kvm_arch_vcpu_load() to warn future
> developers about maintaining the 'csr_dirty' dependency, as Andrew's
> suggestion to reduce fragility.
> - Removed unnecessary single-line comments and fixed indentation nits.
>
> v3 -> v4:
> - Addressed Anup Patel's review regarding hardware state inconsistency.
> - Introduced 'csr_dirty' flag to track dynamic userspace CSR/CONFIG
> modifications (KVM_SET_ONE_REG, KVM_SET_GUEST_DEBUG), forcing a full
> restore when debugging or modifying states at userspace.
> - Kept kvm_riscv_vcpu_aia_load() out of the skip block to resolve IMSIC
> VS-file instability.
>
> v2 -> v3:
> v2 was missing a critical check because I generated the patch from my
> wrong (experimental) branch. This is fixed in v3. Sorry for my trouble.
>
> v1 -> v2:
> Apply the logic to aia csr load. Thanks for Andrew Jones's advice.
> ---
> arch/riscv/include/asm/kvm_host.h | 3 +++
> arch/riscv/kvm/vcpu.c | 24 ++++++++++++++++++++++--
> arch/riscv/kvm/vcpu_onereg.c | 2 ++
> 3 files changed, 27 insertions(+), 2 deletions(-)
>
> diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h
> index 24585304c..7ee47b83c 100644
> --- a/arch/riscv/include/asm/kvm_host.h
> +++ b/arch/riscv/include/asm/kvm_host.h
> @@ -273,6 +273,9 @@ struct kvm_vcpu_arch {
> /* 'static' configurations which are set only once */
> struct kvm_vcpu_config cfg;
>
> + /* Indicates modified guest CSRs */
> + bool csr_dirty;
> +
> /* SBI steal-time accounting */
> struct {
> gpa_t shmem;
> diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c
> index a55a95da5..2e4dfff07 100644
> --- a/arch/riscv/kvm/vcpu.c
> +++ b/arch/riscv/kvm/vcpu.c
> @@ -24,6 +24,8 @@
> #define CREATE_TRACE_POINTS
> #include "trace.h"
>
> +static DEFINE_PER_CPU(struct kvm_vcpu *, kvm_former_vcpu);
> +
> const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
> KVM_GENERIC_VCPU_STATS(),
> STATS_DESC_COUNTER(VCPU, ecall_exit_stat),
> @@ -537,6 +539,8 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
> vcpu->arch.cfg.hedeleg |= BIT(EXC_BREAKPOINT);
> }
>
> + vcpu->arch.csr_dirty = true;
> +
> return 0;
> }
>
> @@ -581,6 +585,21 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
> struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
> struct kvm_vcpu_config *cfg = &vcpu->arch.cfg;
>
> + /*
> + * If VCPU is being reloaded on the same physical CPU and no
> + * other KVM VCPU has run on this CPU since it was last put,
> + * we can skip the expensive CSR and HGATP writes.
> + *
> + * Note: If a new CSR is added to this fast-path skip block,
> + * make sure that 'csr_dirty' is set to true in any
> + * ioctl (e.g., KVM_SET_ONE_REG) that modifies it.
> + */
> + if (vcpu != __this_cpu_read(kvm_former_vcpu))
> + __this_cpu_write(kvm_former_vcpu, vcpu);
> + else if (vcpu->arch.last_exit_cpu == cpu && !vcpu->arch.csr_dirty)
> + goto csr_restore_done;
> +
> + vcpu->arch.csr_dirty = false;
> if (kvm_riscv_nacl_sync_csr_available()) {
> nsh = nacl_shmem();
> nacl_csr_write(nsh, CSR_VSSTATUS, csr->vsstatus);
> @@ -624,6 +643,9 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
>
> kvm_riscv_mmu_update_hgatp(vcpu);
>
> + kvm_riscv_vcpu_aia_load(vcpu, cpu);
> +
> +csr_restore_done:
> kvm_riscv_vcpu_timer_restore(vcpu);
>
> kvm_riscv_vcpu_host_fp_save(&vcpu->arch.host_context);
> @@ -633,8 +655,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
> kvm_riscv_vcpu_guest_vector_restore(&vcpu->arch.guest_context,
> vcpu->arch.isa);
>
> - kvm_riscv_vcpu_aia_load(vcpu, cpu);
> -
> kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu);
>
> vcpu->cpu = cpu;
> diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c
> index e7ab6cb00..fc08bf833 100644
> --- a/arch/riscv/kvm/vcpu_onereg.c
> +++ b/arch/riscv/kvm/vcpu_onereg.c
> @@ -652,6 +652,8 @@ static int kvm_riscv_vcpu_set_reg_csr(struct kvm_vcpu *vcpu,
> if (rc)
> return rc;
>
> + vcpu->arch.csr_dirty = true;
> +
> return 0;
> }
>
> --
> 2.43.0
>
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v7] KVM: riscv: Skip CSR restore if VCPU is reloaded on the same core
@ 2026-04-02 13:28 ` Anup Patel
0 siblings, 0 replies; 15+ messages in thread
From: Anup Patel @ 2026-04-02 13:28 UTC (permalink / raw)
To: Jinyu Tang
Cc: Radim Krčmář, Atish Patra, Andrew Jones,
Conor Dooley, Yong-Xuan Wang, Nutty Liu, Paul Walmsley,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, kvm,
kvm-riscv, linux-riscv, linux-kernel
On Fri, Feb 27, 2026 at 5:40 PM Jinyu Tang <tjytimi@163.com> wrote:
>
> Currently, kvm_arch_vcpu_load() unconditionally restores guest CSRs,
> HGATP, and AIA state. However, when a VCPU is loaded back on the same
> physical CPU, and no other KVM VCPU has run on this CPU since it was
> last put, the hardware CSRs and AIA registers are still valid.
>
> This patch optimizes the vcpu_load path by skipping the expensive CSR
> and AIA writes if all the following conditions are met:
> 1. It is being reloaded on the same CPU (vcpu->arch.last_exit_cpu == cpu).
> 2. The CSRs are not dirty (!vcpu->arch.csr_dirty).
> 3. No other VCPU used this CPU (vcpu == __this_cpu_read(kvm_former_vcpu)).
>
> To ensure this fast-path doesn't break corner cases:
> - Live migration and VCPU reset are naturally safe. KVM initializes
> last_exit_cpu to -1, which guarantees the fast-path won't trigger.
> - The 'csr_dirty' flag tracks runtime userspace interventions. If
> userspace modifies guest configurations (e.g., hedeleg via
> KVM_SET_GUEST_DEBUG, or CSRs including AIA via KVM_SET_ONE_REG),
> the flag is set to skip the fast path.
>
> With the 'csr_dirty' safeguard proven effective, it is safe to
> include kvm_riscv_vcpu_aia_load() inside the skip logic now.
>
> Signed-off-by: Jinyu Tang <tjytimi@163.com>
Queued this patch for Linux-7.1
Thanks,
Anup
> ---
> v6 -> v7:
> - Moved kvm_riscv_vcpu_aia_load() into the fast-path skip logic, as
> suggested by Radim Krčmář.
> - Verified the fix for the IMSIC instability issue reported in v3.
> Testing was conducted on QEMU 10.0.2 with explicitly enabled AIA
> (`-machine virt,aia=aplic-imsic`). The guest boots successfully
> using virtio-mmio devices like virtio-blk and virtio-net.
>
> v5 -> v6:
> As suggested by Andrew Jones, checking 'last_exit_cpu' first (most
> likely to fail on busy hosts) and placing the expensive
> __this_cpu_read() last, skipping __this_cpu_write() in kvm_arch_vcpu_put()
> if kvm_former_vcpu is already set to the current VCPU.
>
> v4 -> v5:
> - Dropped the 'vcpu->scheduled_out' check as Andrew Jones pointed out,
> relying on 'last_exit_cpu', 'former_vcpu', and '!csr_dirty'
> is sufficient and safe. This expands the optimization to cover many
> userspace exits (e.g., MMIO) as well.
> - Added a block comment in kvm_arch_vcpu_load() to warn future
> developers about maintaining the 'csr_dirty' dependency, as Andrew's
> suggestion to reduce fragility.
> - Removed unnecessary single-line comments and fixed indentation nits.
>
> v3 -> v4:
> - Addressed Anup Patel's review regarding hardware state inconsistency.
> - Introduced 'csr_dirty' flag to track dynamic userspace CSR/CONFIG
> modifications (KVM_SET_ONE_REG, KVM_SET_GUEST_DEBUG), forcing a full
> restore when debugging or modifying states at userspace.
> - Kept kvm_riscv_vcpu_aia_load() out of the skip block to resolve IMSIC
> VS-file instability.
>
> v2 -> v3:
> v2 was missing a critical check because I generated the patch from my
> wrong (experimental) branch. This is fixed in v3. Sorry for my trouble.
>
> v1 -> v2:
> Apply the logic to aia csr load. Thanks for Andrew Jones's advice.
> ---
> arch/riscv/include/asm/kvm_host.h | 3 +++
> arch/riscv/kvm/vcpu.c | 24 ++++++++++++++++++++++--
> arch/riscv/kvm/vcpu_onereg.c | 2 ++
> 3 files changed, 27 insertions(+), 2 deletions(-)
>
> diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h
> index 24585304c..7ee47b83c 100644
> --- a/arch/riscv/include/asm/kvm_host.h
> +++ b/arch/riscv/include/asm/kvm_host.h
> @@ -273,6 +273,9 @@ struct kvm_vcpu_arch {
> /* 'static' configurations which are set only once */
> struct kvm_vcpu_config cfg;
>
> + /* Indicates modified guest CSRs */
> + bool csr_dirty;
> +
> /* SBI steal-time accounting */
> struct {
> gpa_t shmem;
> diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c
> index a55a95da5..2e4dfff07 100644
> --- a/arch/riscv/kvm/vcpu.c
> +++ b/arch/riscv/kvm/vcpu.c
> @@ -24,6 +24,8 @@
> #define CREATE_TRACE_POINTS
> #include "trace.h"
>
> +static DEFINE_PER_CPU(struct kvm_vcpu *, kvm_former_vcpu);
> +
> const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
> KVM_GENERIC_VCPU_STATS(),
> STATS_DESC_COUNTER(VCPU, ecall_exit_stat),
> @@ -537,6 +539,8 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
> vcpu->arch.cfg.hedeleg |= BIT(EXC_BREAKPOINT);
> }
>
> + vcpu->arch.csr_dirty = true;
> +
> return 0;
> }
>
> @@ -581,6 +585,21 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
> struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
> struct kvm_vcpu_config *cfg = &vcpu->arch.cfg;
>
> + /*
> + * If VCPU is being reloaded on the same physical CPU and no
> + * other KVM VCPU has run on this CPU since it was last put,
> + * we can skip the expensive CSR and HGATP writes.
> + *
> + * Note: If a new CSR is added to this fast-path skip block,
> + * make sure that 'csr_dirty' is set to true in any
> + * ioctl (e.g., KVM_SET_ONE_REG) that modifies it.
> + */
> + if (vcpu != __this_cpu_read(kvm_former_vcpu))
> + __this_cpu_write(kvm_former_vcpu, vcpu);
> + else if (vcpu->arch.last_exit_cpu == cpu && !vcpu->arch.csr_dirty)
> + goto csr_restore_done;
> +
> + vcpu->arch.csr_dirty = false;
> if (kvm_riscv_nacl_sync_csr_available()) {
> nsh = nacl_shmem();
> nacl_csr_write(nsh, CSR_VSSTATUS, csr->vsstatus);
> @@ -624,6 +643,9 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
>
> kvm_riscv_mmu_update_hgatp(vcpu);
>
> + kvm_riscv_vcpu_aia_load(vcpu, cpu);
> +
> +csr_restore_done:
> kvm_riscv_vcpu_timer_restore(vcpu);
>
> kvm_riscv_vcpu_host_fp_save(&vcpu->arch.host_context);
> @@ -633,8 +655,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
> kvm_riscv_vcpu_guest_vector_restore(&vcpu->arch.guest_context,
> vcpu->arch.isa);
>
> - kvm_riscv_vcpu_aia_load(vcpu, cpu);
> -
> kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu);
>
> vcpu->cpu = cpu;
> diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c
> index e7ab6cb00..fc08bf833 100644
> --- a/arch/riscv/kvm/vcpu_onereg.c
> +++ b/arch/riscv/kvm/vcpu_onereg.c
> @@ -652,6 +652,8 @@ static int kvm_riscv_vcpu_set_reg_csr(struct kvm_vcpu *vcpu,
> if (rc)
> return rc;
>
> + vcpu->arch.csr_dirty = true;
> +
> return 0;
> }
>
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v7] KVM: riscv: Skip CSR restore if VCPU is reloaded on the same core
@ 2026-04-02 13:28 ` Anup Patel
0 siblings, 0 replies; 15+ messages in thread
From: Anup Patel @ 2026-04-02 13:28 UTC (permalink / raw)
To: Jinyu Tang
Cc: Radim Krčmář, Atish Patra, Andrew Jones,
Conor Dooley, Yong-Xuan Wang, Nutty Liu, Paul Walmsley,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, kvm,
kvm-riscv, linux-riscv, linux-kernel
On Fri, Feb 27, 2026 at 5:40 PM Jinyu Tang <tjytimi@163.com> wrote:
>
> Currently, kvm_arch_vcpu_load() unconditionally restores guest CSRs,
> HGATP, and AIA state. However, when a VCPU is loaded back on the same
> physical CPU, and no other KVM VCPU has run on this CPU since it was
> last put, the hardware CSRs and AIA registers are still valid.
>
> This patch optimizes the vcpu_load path by skipping the expensive CSR
> and AIA writes if all the following conditions are met:
> 1. It is being reloaded on the same CPU (vcpu->arch.last_exit_cpu == cpu).
> 2. The CSRs are not dirty (!vcpu->arch.csr_dirty).
> 3. No other VCPU used this CPU (vcpu == __this_cpu_read(kvm_former_vcpu)).
>
> To ensure this fast-path doesn't break corner cases:
> - Live migration and VCPU reset are naturally safe. KVM initializes
> last_exit_cpu to -1, which guarantees the fast-path won't trigger.
> - The 'csr_dirty' flag tracks runtime userspace interventions. If
> userspace modifies guest configurations (e.g., hedeleg via
> KVM_SET_GUEST_DEBUG, or CSRs including AIA via KVM_SET_ONE_REG),
> the flag is set to skip the fast path.
>
> With the 'csr_dirty' safeguard proven effective, it is safe to
> include kvm_riscv_vcpu_aia_load() inside the skip logic now.
>
> Signed-off-by: Jinyu Tang <tjytimi@163.com>
Queued this patch for Linux-7.1
Thanks,
Anup
> ---
> v6 -> v7:
> - Moved kvm_riscv_vcpu_aia_load() into the fast-path skip logic, as
> suggested by Radim Krčmář.
> - Verified the fix for the IMSIC instability issue reported in v3.
> Testing was conducted on QEMU 10.0.2 with explicitly enabled AIA
> (`-machine virt,aia=aplic-imsic`). The guest boots successfully
> using virtio-mmio devices like virtio-blk and virtio-net.
>
> v5 -> v6:
> As suggested by Andrew Jones, checking 'last_exit_cpu' first (most
> likely to fail on busy hosts) and placing the expensive
> __this_cpu_read() last, skipping __this_cpu_write() in kvm_arch_vcpu_put()
> if kvm_former_vcpu is already set to the current VCPU.
>
> v4 -> v5:
> - Dropped the 'vcpu->scheduled_out' check as Andrew Jones pointed out,
> relying on 'last_exit_cpu', 'former_vcpu', and '!csr_dirty'
> is sufficient and safe. This expands the optimization to cover many
> userspace exits (e.g., MMIO) as well.
> - Added a block comment in kvm_arch_vcpu_load() to warn future
> developers about maintaining the 'csr_dirty' dependency, as Andrew's
> suggestion to reduce fragility.
> - Removed unnecessary single-line comments and fixed indentation nits.
>
> v3 -> v4:
> - Addressed Anup Patel's review regarding hardware state inconsistency.
> - Introduced 'csr_dirty' flag to track dynamic userspace CSR/CONFIG
> modifications (KVM_SET_ONE_REG, KVM_SET_GUEST_DEBUG), forcing a full
> restore when debugging or modifying states at userspace.
> - Kept kvm_riscv_vcpu_aia_load() out of the skip block to resolve IMSIC
> VS-file instability.
>
> v2 -> v3:
> v2 was missing a critical check because I generated the patch from my
> wrong (experimental) branch. This is fixed in v3. Sorry for my trouble.
>
> v1 -> v2:
> Apply the logic to aia csr load. Thanks for Andrew Jones's advice.
> ---
> arch/riscv/include/asm/kvm_host.h | 3 +++
> arch/riscv/kvm/vcpu.c | 24 ++++++++++++++++++++++--
> arch/riscv/kvm/vcpu_onereg.c | 2 ++
> 3 files changed, 27 insertions(+), 2 deletions(-)
>
> diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h
> index 24585304c..7ee47b83c 100644
> --- a/arch/riscv/include/asm/kvm_host.h
> +++ b/arch/riscv/include/asm/kvm_host.h
> @@ -273,6 +273,9 @@ struct kvm_vcpu_arch {
> /* 'static' configurations which are set only once */
> struct kvm_vcpu_config cfg;
>
> + /* Indicates modified guest CSRs */
> + bool csr_dirty;
> +
> /* SBI steal-time accounting */
> struct {
> gpa_t shmem;
> diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c
> index a55a95da5..2e4dfff07 100644
> --- a/arch/riscv/kvm/vcpu.c
> +++ b/arch/riscv/kvm/vcpu.c
> @@ -24,6 +24,8 @@
> #define CREATE_TRACE_POINTS
> #include "trace.h"
>
> +static DEFINE_PER_CPU(struct kvm_vcpu *, kvm_former_vcpu);
> +
> const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
> KVM_GENERIC_VCPU_STATS(),
> STATS_DESC_COUNTER(VCPU, ecall_exit_stat),
> @@ -537,6 +539,8 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
> vcpu->arch.cfg.hedeleg |= BIT(EXC_BREAKPOINT);
> }
>
> + vcpu->arch.csr_dirty = true;
> +
> return 0;
> }
>
> @@ -581,6 +585,21 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
> struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
> struct kvm_vcpu_config *cfg = &vcpu->arch.cfg;
>
> + /*
> + * If VCPU is being reloaded on the same physical CPU and no
> + * other KVM VCPU has run on this CPU since it was last put,
> + * we can skip the expensive CSR and HGATP writes.
> + *
> + * Note: If a new CSR is added to this fast-path skip block,
> + * make sure that 'csr_dirty' is set to true in any
> + * ioctl (e.g., KVM_SET_ONE_REG) that modifies it.
> + */
> + if (vcpu != __this_cpu_read(kvm_former_vcpu))
> + __this_cpu_write(kvm_former_vcpu, vcpu);
> + else if (vcpu->arch.last_exit_cpu == cpu && !vcpu->arch.csr_dirty)
> + goto csr_restore_done;
> +
> + vcpu->arch.csr_dirty = false;
> if (kvm_riscv_nacl_sync_csr_available()) {
> nsh = nacl_shmem();
> nacl_csr_write(nsh, CSR_VSSTATUS, csr->vsstatus);
> @@ -624,6 +643,9 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
>
> kvm_riscv_mmu_update_hgatp(vcpu);
>
> + kvm_riscv_vcpu_aia_load(vcpu, cpu);
> +
> +csr_restore_done:
> kvm_riscv_vcpu_timer_restore(vcpu);
>
> kvm_riscv_vcpu_host_fp_save(&vcpu->arch.host_context);
> @@ -633,8 +655,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
> kvm_riscv_vcpu_guest_vector_restore(&vcpu->arch.guest_context,
> vcpu->arch.isa);
>
> - kvm_riscv_vcpu_aia_load(vcpu, cpu);
> -
> kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu);
>
> vcpu->cpu = cpu;
> diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c
> index e7ab6cb00..fc08bf833 100644
> --- a/arch/riscv/kvm/vcpu_onereg.c
> +++ b/arch/riscv/kvm/vcpu_onereg.c
> @@ -652,6 +652,8 @@ static int kvm_riscv_vcpu_set_reg_csr(struct kvm_vcpu *vcpu,
> if (rc)
> return rc;
>
> + vcpu->arch.csr_dirty = true;
> +
> return 0;
> }
>
> --
> 2.43.0
>
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2026-04-02 13:28 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-27 12:10 [PATCH v7] KVM: riscv: Skip CSR restore if VCPU is reloaded on the same core Jinyu Tang
2026-02-27 12:10 ` Jinyu Tang
2026-02-27 12:10 ` Jinyu Tang
2026-02-27 14:00 ` Radim Krčmář
2026-02-27 14:00 ` Radim Krčmář
2026-02-27 14:00 ` Radim Krčmář
2026-03-02 22:18 ` Andrew Jones
2026-03-02 22:18 ` Andrew Jones
2026-03-02 22:18 ` Andrew Jones
2026-03-03 3:13 ` Nutty.Liu
2026-03-03 3:13 ` Nutty.Liu
2026-03-03 3:13 ` Nutty.Liu
2026-04-02 13:28 ` Anup Patel
2026-04-02 13:28 ` Anup Patel
2026-04-02 13:28 ` Anup Patel
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.