On 9/30/2026 6:39 AM, Wang Yechao wrote:
When a VM reset is requested, KVM needs to reset the register state of
the vCPUs. Without this, stale KVM-internal vCPU state (such as the SBI
STA shared memory address) is preserved across the reset, which can
cause KVM to keep writing steal-time data to an address that now belongs
to firmware code, corrupting it.

Add support for the KVM_CAP_RISCV_MP_STATE_RESET capability. When
enabled, QEMU resets the vCPU by setting MP_STATE_INIT_RECEIVED through
the KVM_SET_MP_STATE ioctl during the KVM_PUT_RESET_STATE phase of
kvm_arch_put_registers(). KVM performs the register reset while
preserving the original MP_STATE, so no state restoration is needed on
the QEMU side.

This reset path is reached both when the guest initiates an SBI system
reset and when userspace (e.g. the QEMU monitor) requests a VM reset,
covering both reboot scenarios.

The capability is optional and only activated if the host kernel
advertises KVM_CAP_RISCV_MP_STATE_RESET, ensuring backward compatibility
with older kernels.

Signed-off-by: Wang Yechao <[email protected]>
---

Reviewed-by: Daniel Henrique Barboza <[email protected]>

  target/riscv/kvm/kvm-cpu.c | 27 +++++++++++++++++++++++++++
  1 file changed, 27 insertions(+)

diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index 68e1501b21..30cea19dea 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -58,6 +58,7 @@ void riscv_kvm_aplic_request(void *opaque, int irq, int level)
  }
static bool cap_has_mp_state;
+static bool mp_state_reset;
#define KVM_RISCV_REG_ID_U32(type, idx) (KVM_REG_RISCV | KVM_REG_SIZE_U32 | \
                                           type | idx)
@@ -1405,10 +1406,31 @@ static int kvm_riscv_put_mp_state(CPUState *cs)
      return kvm_vcpu_ioctl(cs, KVM_SET_MP_STATE, &mp_state);
  }
+static int kvm_riscv_mp_state_init_received(CPUState *cs)
+{
+    struct kvm_mp_state mp_state = {
+        .mp_state = KVM_MP_STATE_INIT_RECEIVED,
+    };
+
+    if (!cap_has_mp_state || !mp_state_reset) {
+        return 0;
+    }
+
+    /* Let KVM resets the VCPU, The original MP_STATE is preserved*/
+    return kvm_vcpu_ioctl(cs, KVM_SET_MP_STATE, &mp_state);
+}
+
  int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp)
  {
      int ret = 0;
+ if (KVM_PUT_RESET_STATE == level) {
+        ret = kvm_riscv_mp_state_init_received(cs);
+        if (ret) {
+            return ret;
+        }
+    }
+
      ret = kvm_riscv_put_regs_core(cs);
      if (ret) {
          return ret;
@@ -1585,6 +1607,11 @@ int kvm_arch_get_default_type(MachineState *ms)
  int kvm_arch_init(MachineState *ms, KVMState *s)
  {
      cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE);
+
+    if (cap_has_mp_state) {
+        mp_state_reset = !kvm_vm_enable_cap(s, KVM_CAP_RISCV_MP_STATE_RESET, 
0);
+    }
+
      return 0;
  }


Reply via email to