target/riscv/kvm/kvm-cpu.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-)
During KVM exit processing (KVM_PUT_RUNTIME_STATE), QEMU never modifies
FP or Vector registers — only core GPRs/PC and CSRs are potentially
changed. Re-syncing 32 FP and 32 Vector registers on every KVM exit
wastes 36-68 individual KVM_SET_ONE_REG ioctls per vCPU exit.
Follow the s390x pattern: early return on RUNTIME after syncing core
registers and CSRs. KVM_PUT_FULL_STATE and KVM_PUT_RESET_STATE continue
to sync everything for correctness during migration and initialization.
Signed-off-by: Meng Zhuo <mengzhuo@iscas.ac.cn>
---
target/riscv/kvm/kvm-cpu.c | 25 +++++++++++++++++--------
1 file changed, 17 insertions(+), 8 deletions(-)
diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index b047ffa9c0..12a440971e 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -1373,7 +1373,7 @@ int kvm_riscv_sync_mpstate_to_kvm(RISCVCPU *cpu, int state)
int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp)
{
- int ret = 0;
+ int ret;
ret = kvm_riscv_put_regs_core(cs);
if (ret) {
@@ -1385,6 +1385,17 @@ int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp)
return ret;
}
+ /*
+ * For RUNTIME_STATE, KVM already has the correct FP and Vector state
+ * from the preceding KVM_RUN exit. QEMU never modifies these registers
+ * during exit handling, so re-syncing is unnecessary. This saves ~68
+ * KVM_SET_ONE_REG ioctls per vCPU exit. See also s390x which uses
+ * the same pattern.
+ */
+ if (level == KVM_PUT_RUNTIME_STATE) {
+ return 0;
+ }
+
ret = kvm_riscv_put_regs_fp(cs);
if (ret) {
return ret;
@@ -1395,19 +1406,17 @@ int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp)
return ret;
}
- if (KVM_PUT_RESET_STATE == level) {
+ if (level == KVM_PUT_RESET_STATE) {
RISCVCPU *cpu = RISCV_CPU(cs);
- if (cs->cpu_index == 0) {
- ret = kvm_riscv_sync_mpstate_to_kvm(cpu, KVM_MP_STATE_RUNNABLE);
- } else {
- ret = kvm_riscv_sync_mpstate_to_kvm(cpu, KVM_MP_STATE_STOPPED);
- }
+ int state = cs->cpu_index == 0 ? KVM_MP_STATE_RUNNABLE
+ : KVM_MP_STATE_STOPPED;
+ ret = kvm_riscv_sync_mpstate_to_kvm(cpu, state);
if (ret) {
return ret;
}
}
- return ret;
+ return 0;
}
int kvm_arch_release_virq_post(int virq)
--
2.47.3
On Wed, May 13, 2026 at 06:04:47PM +0800, Meng Zhuo wrote:
> During KVM exit processing (KVM_PUT_RUNTIME_STATE), QEMU never modifies
> FP or Vector registers — only core GPRs/PC and CSRs are potentially
> changed. Re-syncing 32 FP and 32 Vector registers on every KVM exit
> wastes 36-68 individual KVM_SET_ONE_REG ioctls per vCPU exit.
>
> Follow the s390x pattern: early return on RUNTIME after syncing core
> registers and CSRs. KVM_PUT_FULL_STATE and KVM_PUT_RESET_STATE continue
> to sync everything for correctness during migration and initialization.
>
> Signed-off-by: Meng Zhuo <mengzhuo@iscas.ac.cn>
> ---
> target/riscv/kvm/kvm-cpu.c | 25 +++++++++++++++++--------
> 1 file changed, 17 insertions(+), 8 deletions(-)
>
> diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
> index b047ffa9c0..12a440971e 100644
> --- a/target/riscv/kvm/kvm-cpu.c
> +++ b/target/riscv/kvm/kvm-cpu.c
> @@ -1373,7 +1373,7 @@ int kvm_riscv_sync_mpstate_to_kvm(RISCVCPU *cpu, int state)
>
> int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp)
> {
> - int ret = 0;
> + int ret;
>
> ret = kvm_riscv_put_regs_core(cs);
> if (ret) {
> @@ -1385,6 +1385,17 @@ int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp)
> return ret;
> }
>
> + /*
> + * For RUNTIME_STATE, KVM already has the correct FP and Vector state
> + * from the preceding KVM_RUN exit. QEMU never modifies these registers
> + * during exit handling, so re-syncing is unnecessary. This saves ~68
> + * KVM_SET_ONE_REG ioctls per vCPU exit. See also s390x which uses
> + * the same pattern.
> + */
> + if (level == KVM_PUT_RUNTIME_STATE) {
> + return 0;
Why do we return 0 directly instead of returning `ret`? Is there any benefit to
doing it this way?
> + }
> +
> ret = kvm_riscv_put_regs_fp(cs);
> if (ret) {
> return ret;
> @@ -1395,19 +1406,17 @@ int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp)
> return ret;
> }
>
> - if (KVM_PUT_RESET_STATE == level) {
> + if (level == KVM_PUT_RESET_STATE) {
This line doesn’t need to be changed.
Thanks,
Chao
> RISCVCPU *cpu = RISCV_CPU(cs);
> - if (cs->cpu_index == 0) {
> - ret = kvm_riscv_sync_mpstate_to_kvm(cpu, KVM_MP_STATE_RUNNABLE);
> - } else {
> - ret = kvm_riscv_sync_mpstate_to_kvm(cpu, KVM_MP_STATE_STOPPED);
> - }
> + int state = cs->cpu_index == 0 ? KVM_MP_STATE_RUNNABLE
> + : KVM_MP_STATE_STOPPED;
> + ret = kvm_riscv_sync_mpstate_to_kvm(cpu, state);
> if (ret) {
> return ret;
> }
> }
>
> - return ret;
> + return 0;
> }
>
> int kvm_arch_release_virq_post(int virq)
> --
> 2.47.3
>
>
© 2016 - 2026 Red Hat, Inc.